我正在尝试编写一个将文件从一个位置复制到另一个位置并报告进度的类。我遇到的问题是,当应用程序运行时,进度将立即从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只是在操作系统中排队操作,而不是在读或写完成之前阻塞。
有没有办法在不造成巨大性能损失的情况下禁用此功能?
PS。我正在使用测试源和目标变量,这就是为什么它们与参数不匹配。
由于 克雷格
答案 0 :(得分:6)
我认为它不能排队读取操作...毕竟,你有一个字节数组,它会在Read
调用之后有一些数据 - 数据最好是正确的。可能只有正在缓冲的 write 操作。
您可以尝试定期在输出流上调用Flush
...我不知道Flush
在各种级别的缓存方面会走多远,但它可能会等待直到数据实际写入。编辑:如果您知道它是FileStream
,您可以调用Flush(true)
,它将等待数据实际写入磁盘。
请注意,您不应经常这样做,否则性能会受到严重影响。您需要平衡进度准确性的粒度与性能损失,以获得更多控制,而不是让操作系统优化磁盘访问。
我担心你在这里使用递归 - 在一个非常大的文件上你可能会因为没有充分理由而堆积溢出。 (CLR有时可以优化尾递归方法,但并非总是如此)。我建议你改用循环。这也更具可读性,IMO:
public void Copy()
{
int bytesRead;
while ((bytesRead = _sourceStream.Read(_buffer, 0, _buffer.Length)) > 0)
{
_destinationStream.Write(_buffer, 0, bytesRead);
_completedBytes += bytesRead;
TriggerProgressUpdate();
if (someAppropriateCondition)
{
_destinationStream.Flush();
}
}
}
顺便说一下,我希望你能在某处处理这些溪流。就个人而言,我尽量避免使用一次性成员变量。你有什么理由不能在using
语句中使用局部变量吗?
答案 1 :(得分:2)
经过调查,我发现在FileStream的构造函数中使用“FileOptions.WriteThrough”将禁用写入缓存。这会导致我的进度正确报告。然而它确实会受到性能影响,复制在Windows中需要13秒,在我的应用程序中需要20秒。我将尝试优化代码并调整缓冲区大小,看看我是否可以加快速度。