Home > database >  FileStream.WriteAsync(buffer.AsMemory(0, read)) won't work when writing small files but CopyToA
FileStream.WriteAsync(buffer.AsMemory(0, read)) won't work when writing small files but CopyToA

Time:01-07

I have small sig files that are exactly 256 bytes. When uploading to a file upload controller on asp.net core web app, the buffer is occupied correctly for the 256 positions but they aren't written to the output stream and the file is empty. CopyToAsync works fine. This will only happen to certain files. The problem is reproducible on a console application:

string SoureFile = @"C:\Users\me\source\repos\files\mySigFile.sig";
byte[] buffer = new byte[1024 * 64];

string tmp = @"C:\Users\me\Downloads\tempsigfile.tmp";
string tmp2 = @"C:\Users\me\Downloads\tempsigfile2.tmp";


var inputStream = File.Open(SoureFile, FileMode.OpenOrCreate);

//doesn't work
using FileStream writer = new(tmp, FileMode.Create);
int read;
while ((read = await inputStream.ReadAsync(buffer)) != 0)
{
    await writer.WriteAsync(buffer.AsMemory(0, read));
}

inputStream.Position = 0;

//works
using (var stream = new FileStream(tmp2, FileMode.Create))
{
    await inputStream.CopyToAsync(stream);
}

FileInfo info = new FileInfo(tmp);

Console.WriteLine(info.Length); //0

FileInfo info2 = new FileInfo(tmp2);

Console.WriteLine(info2.Length);//256

CodePudding user response:

Doing this (using declaration, no bracers):

using FileStream writer = new(tmp, FileMode.Create);

means writer will only be disposed at the end of the scope, so at the end of the method. Doing WriteAsync does not necessary mean that information will be written to file right away, it might be written to the internal in-memory buffer and only written to the file when this buffer fills or when you close the file, or when you explicitly call Flush on a stream. You don't do anything of that, the file is only closed at the end of the method, but your check:

FileInfo info = new FileInfo(tmp);
Console.WriteLine(info.Length); //0

is performed before the actual write to file happens, so you see 0. If you actually check the contents of the file after this method (program) completes - you'll see it contains the correct data.

In second case you use using statement:

using (var stream = new FileStream(tmp2, FileMode.Create))
{
    await inputStream.CopyToAsync(stream);
}

so you write to a file, close it, and only after that check the contents. Then it works as you expect.

  •  Tags:  
  • c#
  • Related