【问题标题】:FileStream.EndWrite throws an exception (.NET)FileStream.EndWrite 引发异常 (.NET)
【发布时间】:2010-07-21 22:44:27
【问题描述】:

我正在尝试在复制文件时实现进度通知机制。 我正在通过以下方式执行此操作:

  1. 我创建了两个 FileStreams - 用于读取和写入
  2. 调用 BeginRead 并传递给它一个 ReadCallback 和一个包含读取流的结构和用于填充从文件中读取的数据的数组。
  3. ReadCallback 中,我调用 EndRead 方法并在用于写入的文件流上调用 BeginWrite 方法,传递给它一个 WriteCallback 以及包含流(用于写入)和要写入的数组(与读取部分相同)的结构。
  4. 当我在 WriteCallback 中调用 EndWrite 并将 asyncResult 传递给它时,它会引发 ArgumentException:IAsyncResult 对象不是来自相应的异步方法在这种类型上,或者 EndRead 被多次调用并使用相同的 IAsyncResult

请帮助解决这个问题。

更新源码:

private void StartAsyncCopying()
{
    var sourceFileInfo = new FileInfo(Source);
    if (!sourceFileInfo.Exists)
    {
        throw new FileNotFoundException("File not found.",
            Source);
    }
    m_sourceLength = sourceFileInfo.Length;
    m_readerStream = new FileStream(Source, FileMode.Open);
    m_writerStream = new FileStream(Target, FileMode.Create);
    m_queueBuffer = new Queue<byte[]>(DefaultQueueBufferSize);
    m_queueBufferLock = new object();

    ProgressRead();
}

private void ProgressRead()
{
    var readerChunck = new byte[DefaultChunckSize];
    var streamChunck = new StreamChunck(readerChunck, m_readerStream);
    m_readerStream.BeginRead(streamChunck.Chunck,
        0,
        streamChunck.Chunck.Length,
        ReadCallback,
        streamChunck);
}


private void ReadCallback(IAsyncResult asyncResult)
{
    var streamChunck = asyncResult.AsyncState as StreamChunck;
    var numberOfBytesRead = streamChunck.Stream.EndRead(asyncResult);

    m_readerOffset += numberOfBytesRead;

    ProgressWrite(streamChunck.Chunck);
}

private void ProgressWrite(byte[] chunck)
{
    var streamChunck = new StreamChunck(chunck, m_writerStream);
    m_writerAsyncResult = m_writerStream.BeginWrite(streamChunck.Chunck,
        0,
        streamChunck.Chunck.Length,
        WriteCallback,
        streamChunck);
}

private void WriteCallback(IAsyncResult asyncResult)
{
    var streamChunck = asyncResult.AsyncState as StreamChunck;
    var numberOfBytesWritten = streamChunck.Stream.EndRead(asyncResult);
    m_writerOffset += numberOfBytesWritten;

    var progressChangedEventArgs = new CopyProgressChangedEventArgs(m_operationDescription,
        m_sourceLength,
        m_writerOffset);
    OnCopyProgressChanged(progressChangedEventArgs);

    if (m_writerOffset == m_sourceLength)
    {
        var copyCompletedEventArgs = new CopyCompletedEventArgs(m_operationDescription, null);
        OnCopyCompleted(copyCompletedEventArgs);
    }
    else
    {
        ProgressRead();
    }
}

【问题讨论】:

  • 能否提供一些示例代码?
  • EndRead 而不是WriteCallback 中的EndWrite,我已经修改了我的答案。
  • 真丢脸!亚当非常感谢您在我的愚蠢问题上花费的宝贵时间
  • 一点也不傻——有时我们只见树木不见森林——每个人都会遇到。在相关说明中,野餐错误意味着“椅子上的问题,而不是电脑上的问题”:-) 快乐编码。

标签: .net filestream


【解决方案1】:

当您调用BeginXXX 时,您可能会得到一个IAsyncResult 对象,要调用EndXXX,您需要将此IAsyncResult 引用传递给方法。如果您使用了 Read 中的相同对象并将其传递给 Write,它将不起作用 - 在您的场景中将有两个单独的 IAsyncResult 对象。

当我这样做时,我会将返回的IAsyncResult 的引用保留为本地类变量(如果使用回调)。当我调用 EndXXX 时,我提供了这个本地引用(从我最初的 BeginXXX 获得),然后将其设为 null 以表示它可以重复使用。

更新 2:查看您的代码,WriteCallback 中的 EndWrite 实际上是 EndRead,野餐错误 :-)

更新 1:以下内容对我来说很好......

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication14
{
    class Program
    {
        static FileStream fs = null;
        static MemoryStream ms = null;
        static byte[] buffer = new byte[512];

        static void Main(string[] args)
        {
            fs = new FileStream("theFile", FileMode.Open);
            fs.BeginRead(buffer, 0, 512, new AsyncCallback(ReadFinished), null);

            Console.Read();
        }

        static void ReadFinished(IAsyncResult res)
        {
            fs.EndRead(res);
            fs.Dispose();

            ms = new MemoryStream();
            ms.BeginWrite(buffer, 0, 512, new AsyncCallback(WriteFinished), null);
        }

        static void WriteFinished(IAsyncResult res)
        {
            ms.EndWrite(res);
            ms.Dispose();
        }
    }
}

【讨论】:

  • 我正在将回调传递给 BeginWrite 方法,但没有从中获取 IAsyncResult 对象。回调具有签名:private void WriteCallback(IAsyncResult asyncResult),并对传递给它的 asyncResult 进行操作。 (在我的阅读对中(BeginRead - ReadCallback 它工作正常)。
  • Adam,感谢您的回答我刚刚尝试过 - 存储 BeginWrite 返回的引用并将其用于回调而不是作为参数传递。再次抛出相同的异常。
  • BeginWriteStream 上返回IAsyncResult。但是,我忘记了包含这个的回调签名,所以它没有实际意义——你不需要使用返回的引用。
  • @Serge 如果是这种情况,那么您在某处存在逻辑错误-尽管我需要查看代码。试试我提供的示例代码,然后替换你自己的文件。
  • ConsoleApplicetion14?你的项目文件夹中有很多默认项目;)
【解决方案2】:

你有以下:

private void WriteCallback(IAsyncResult asyncResult)
{
    var streamChunck = asyncResult.AsyncState as StreamChunck;
    var numberOfBytesWritten = streamChunck.Stream.EndRead(asyncResult);
                                                   ^^^^^^^

但你正在写作。你不应该打电话给EndWrite吗?还是我遗漏了一些非常明显的东西?

该方法中还有一个ProgressRead();

【讨论】:

  • 是的,应该有 EndWrite 谢谢你,ChrisF
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-11
  • 2012-11-05
  • 1970-01-01
  • 2010-09-21
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多