在写/读操作完成之前,C#Filestream不会阻塞

Cra*_*igt 1 c# filestream

我正在尝试编写一个将文件从一个位置复制到另一个位置并报告进度的类.我遇到的问题是,当应用程序运行时,进度将立即从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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

似乎正在发生的事情是FileStream只是在操作系统中排队操作,而不是在读或写完成之前阻塞.

有没有办法在不造成巨大性能损失的情况下禁用此功能?

PS.我正在使用测试源和目标变量,这就是为什么它们与参数不匹配.

谢谢克雷格

Jon*_*eet 6

我不认为它可以排队读取操作...毕竟,你有一个字节数组,它将在Read调用后有一些数据- 数据最好是正确的.它可能只是被缓冲的操作.

您可以尝试Flush定期调用输出流...我不知道Flush在各种级别的缓存方面会有多远,但它可能会等到数据实际写入.编辑:如果您知道它是a 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我希望你能在某处处理这些溪流.就个人而言,我尽量避免使用一次性成员变量.你有什么理由不能在using声明中使用局部变量吗?

  • @Vijay:处理对象对GC没有任何作用.但是在这种情况下,当你完成复制对象时,你就完成了*流.如果你在逻辑上长时间拥有一个对象,那么将它嵌入另一个对象中是有意义的.但是在这里,每次我们调用`Copy(source,target)`它都会替换变量.我看不到在这里有成员变量的任何用途. (3认同)