简体   繁体   中英

FileStream.WriteAsync(buffer.AsMemory(0, read)) won't work when writing small files but CopyToAsync will

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM