FileStream.WriteAsync(buffer.AsMemory(0, read)) 在写入小文件时不起作用,但 CopyToAsync 会



我有刚好256字节的小签名文件。当上载到asp.net core web应用程序上的文件上传控制器时,缓冲区被正确地占用了256个位置,但它们没有写入输出流,文件为空。CopyToAsync工作良好。这只会发生在某些文件上。这个问题在控制台应用程序中重现:

string SoureFile = @"C:UsersmesourcereposfilesmySigFile.sig";
byte[] buffer = new byte[1024 * 64];
string tmp = @"C:UsersmeDownloadstempsigfile.tmp";
string tmp2 = @"C:UsersmeDownloadstempsigfile2.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

这样做(使用声明,不使用括号):

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

表示writer只会在作用域的末尾被处理,也就是在方法的末尾。执行WriteAsync并不一定意味着信息将立即写入文件,它可能被写入内部内存缓冲区,并且只有在缓冲区填充或关闭文件时才写入文件,或者在流上显式调用Flush时才写入文件。你不做任何事情,文件只在方法结束时关闭,但是你的检查:

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

在实际写入文件之前执行,所以您看到的是0。如果在此方法(程序)完成后实际检查文件的内容,您将看到它包含正确的数据。

第二种情况使用using语句:

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

所以你写入一个文件,关闭它,然后检查内容。那么它就会像你期望的那样工作。

最新更新