Yogi
Yogi

Reputation: 450

System.IO.File.WriteAllBytes issue when used for uploading .docx document

I have code like this to accept file upload from Web UI:

        byte[] addBytes = new byte[] { 45, 45 };
        var uploadedFiles = this.HttpContext.Request.Form.Files;
        foreach (var uploadedFile in uploadedFiles)
        {
            filename = uploadedFile.FileName;
            fileFullPath = Path.Combine(uploadFolderName, filename);
            using (Stream bodyStream = uploadedFile.OpenReadStream())
            {
                byte[] contents = await bodyStream.ToByteArrayAsync((int)this.HttpContext.Request.ContentLength);
                if (filename.ToLower().EndsWith(".docx"))
                {
                    contents.Append<byte>(addBytes[0]);
                    contents.Append<byte>(addBytes[1]);
                }
                System.IO.File.WriteAllBytes(fileFullPath, contents);
            }
        } 

the addBytes was supposed to fix the problem but it did not make any difference. When I'm trying to open the docx document, I'm still prompted with this message: "Word found unreadable content in ..... Do you want to recover the contents of this document? If you trust the source of this document, click Yes" .

Does anyone know how to make WriteAllByte work without tripping that message? This code works with other formats, and even some .docx would open fine too. Only most .docx are corrupted

Upvotes: 0

Views: 372

Answers (1)

Etienne de Martel
Etienne de Martel

Reputation: 36851

this.HttpContext.Request.ContentLength is the length of the entire request. Assuming this is a multipart/form-data request, that is bigger than the size of the file, because, well there might be more than one file, and also it includes things like boundaries and the headers of each part. To get the size of the file, use the Length property on the form file.

But really, this is unnecessary. In general, I don't like using File.WriteAllBytes unless you already have a byte array as input, because then it means you'll have to copy your source data to an array and hold it in memory, which is bad for large files. Just use a FileStream and directly copy the data, using IFormFile's CopyToAsync method.

foreach (var uploadedFile in uploadedFiles)
{
    var fullPath = Path.Combine(uploadFolderName, uploadedFile.FileName);
    using var stream = File.Open(fullPath, FileMode.Create, FileAccess.Write);
    await uploadedFile.CopyToAsync(stream);
} 

There. This is shorter, clearer, more efficient, and faster.

Upvotes: 4

Related Questions