简体   繁体   English

C#文件流在写/读操作完成之前不会阻塞

[英]C# Filestream not blocking until write/read operation complete

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. 我遇到的问题是,当应用程序运行时,进度会立即从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);
        }
    }

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. 似乎正在发生的事情是FileStream仅在OS中排队操作,而不是阻塞直到读取或写入完成。

Is there any way to disable this functionality without causing a huge performance loss? 有什么方法可以禁用此功能而不会造成巨大的性能损失?

PS. PS。 I am using test source and destination variables, thats why they dont match the arguments. 我正在使用测试源和目标变量,这就是为什么它们不匹配参数的原因。

Thanks Craig 谢谢克雷格

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. 我不认为它可以使读取操作排队...毕竟,您有一个字节数组,在Read调用后它将有一些数据-数据最好是正确的。 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 the Flush will go in terms of the various levels of caching, but it may well wait until the data has actually been written. 您可以尝试定期在输出流上调用Flush ...我不知道Flush在各种缓存级别上会走多远,但它可能要等到实际写入数据之后才能进行。 EDIT: If you know it's a FileStream , you can call Flush(true) which will wait until the data has actually been written to disk. 编辑:如果您知道这是FileStream ,则可以调用Flush(true) ,它将等待直到数据实际写入磁盘为止。

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). (CLR有时可以优化尾递归方法,但并非总是如此)。 I suggest you use a loop instead. 我建议您改用循环。 That would also be more readable, 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();
        }
    }
}

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? 有什么原因不能只在using语句中使用局部变量?

After investigating I found that using "FileOptions.WriteThrough" in a FileStream's constructor will disable write caching. 经过调查,我发现在FileStream的构造函数中使用“ FileOptions.WriteThrough”将禁用写缓存。 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. 但是,它确实会降低性能,副本在Windows中花费13秒,在我的应用程序中花费20秒。 I'm going to try and optimize the code and adjust the buffer size to see if I can speeds things up a bit. 我将尝试优化代码并调整缓冲区大小,以查看是否可以加快速度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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