C# 文件流在写/读操作完成之前不会阻塞
我正在尝试编写一个类,它将文件从一个位置复制到另一个位置并报告进度。我遇到的问题是,当应用程序运行时,进度会立即从 0 到 100%,但文件仍在后台复制。
public void Copy(string sourceFile, string destinationFile)
{
_stopWatch.Start();
_sourceStream = new FileStream(srcName, FileMode.Open);
_destinationStream = new FileStream(destName, FileMode.CreateNew);
read();
//On a 500mb file, execution will reach here in about a second.
}
private void read()
{
int i = _sourceStream.Read(_buffer, 0, bufferSize);
_completedBytes += i;
if (i != 0)
{
_destinationStream.Write(_buffer, 0, i);
TriggerProgressUpdate();
read();
}
}
private void TriggerProgressUpdate()
{
if (OnCopyProgress != null)
{
CopyProgressEventArgs arg = new CopyProgressEventArgs();
arg.CompleteBytes = _completedBytes;
if (_totalBytes == 0)
_totalBytes = new FileInfo(srcName).Length;
arg.TotalBytes = _totalBytes;
OnCopyProgress(this, arg);
}
}
似乎正在发生的事情是 FileStream 只是在操作系统中对操作进行排队,而不是阻塞直到读取或写入完成。
有没有什么方法可以禁用此功能而不造成巨大的性能损失?
附言。我正在使用测试源和目标变量,这就是它们与参数不匹配的原因。
谢谢 克雷格
I'm trying to write a class that will copy a file from one location to another and report progress. The problem that I'm having is that when the application is run, the progress will shoot from 0 to 100% instantly, but the file is still copying in the background.
public void Copy(string sourceFile, string destinationFile)
{
_stopWatch.Start();
_sourceStream = new FileStream(srcName, FileMode.Open);
_destinationStream = new FileStream(destName, FileMode.CreateNew);
read();
//On a 500mb file, execution will reach here in about a second.
}
private void read()
{
int i = _sourceStream.Read(_buffer, 0, bufferSize);
_completedBytes += i;
if (i != 0)
{
_destinationStream.Write(_buffer, 0, i);
TriggerProgressUpdate();
read();
}
}
private void TriggerProgressUpdate()
{
if (OnCopyProgress != null)
{
CopyProgressEventArgs arg = new CopyProgressEventArgs();
arg.CompleteBytes = _completedBytes;
if (_totalBytes == 0)
_totalBytes = new FileInfo(srcName).Length;
arg.TotalBytes = _totalBytes;
OnCopyProgress(this, arg);
}
}
What seems to be happening is that FileStream is merely queuing the operations in the OS, instead of blocking until the read or write is complete.
Is there any way to disable this functionality without causing a huge performance loss?
PS. I am using test source and destination variables, thats why they dont match the arguments.
Thanks
Craig
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不认为它可以对读取操作进行排队...毕竟,您有一个字节数组,在读取调用后它会包含一些数据- 数据最好是正确的。可能只有写入操作被缓冲。
您可以尝试定期在输出流上调用
Flush
...我不太清楚Flush
在不同级别的缓存方面会走多远,但它可能会等到数据实际写入。编辑:如果您知道它是一个 FileStream,您可以调用 Flush(true) ,它将等待数据实际写入磁盘。请注意,您不应该经常这样做,否则性能会受到严重影响。您需要平衡进度准确性的粒度与采取更多控制而不是让操作系统优化磁盘访问的性能损失。
我担心你在这里使用递归 - 在一个非常大的文件上,你很可能会无缘无故地因堆栈溢出而崩溃。 (CLR 有时可以优化尾递归方法,但并非总是如此)。我建议你改用循环。 IMO:这也更具可读性:
顺便说一句,我希望您在某个地方处理流。就我个人而言,如果可能的话,我会尽量避免使用一次性成员变量。有什么理由不能在
using
语句中使用局部变量吗?I don't think it can be queuing the read operations... after all, you've got a byte array, it will have some data in after the
Read
call - that data had better be correct. It's probably only the write operations which are being buffered.You could try calling
Flush
on the output stream periodically... I don't know quite how far theFlush
will go in terms of the various levels of caching, but it may well wait until the data has actually been written. EDIT: If you know it's aFileStream
, you can callFlush(true)
which will wait until the data has actually been written to disk.Note that you shouldn't do this too often, or performance will suffer significantly. You'll need to balance the granularity of progress accuracy with the performance penalty for taking more control instead of letting the OS optimize the disk access.
I'm concerned about your use of recursion here - on a very large file you may well blow up with a stack overflow for no good reason. (The CLR can sometimes optimize tail-recursive methods, but not always). I suggest you use a loop instead. That would also be more readable, IMO:
I hope you're disposing of the streams somewhere, by the way. Personally I try to avoid having disposable member variables if at all possible. Is there any reason you can't just use local variables in a
using
statement?经过调查,我发现在 FileStream 的构造函数中使用“FileOptions.WriteThrough”将禁用写入缓存。这使得我的进度能够正确报告。然而,它确实会影响性能,在 Windows 中复制需要 13 秒,在我的应用程序中需要 20 秒。我将尝试优化代码并调整缓冲区大小,看看是否可以加快速度。
After investigating I found that using "FileOptions.WriteThrough" in a FileStream's constructor will disable write caching. This causes my progress to report correctly. It does however take a performance hit, the copy takes 13 seconds in windows and 20 second in my application. I'm going to try and optimize the code and adjust the buffer size to see if I can speeds things up a bit.