FileStream.EndWrite генерирует исключение (.NET) - PullRequest
0 голосов
/ 21 июля 2010

Я пытаюсь реализовать механизм уведомления о прогрессе при копировании файлов. Я делаю это следующим образом:

  1. Я создаю два FileStreams - для чтения и записи
  2. Вызовите BeginRead , передав ему ReadCallback и структуру, содержащую поток чтения и массив для заполнения данными, считанными из файла.
  3. В ReadCallback я вызываю метод EndRead и вызываю метод BeginWrite в файловом потоке, используемом для записи, передавая ему WriteCallback и структура, содержащая поток (используемый для записи) и массив для записи (такой же, как и для чтения).
  4. Когда я вызываю EndWrite в WriteCallback , передавая ему asyncResult, он выдает ArgumentException: либо объект IAsyncResult не получен из соответствующего асинхронного метода на этом type, или 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();
    }
}

Ответы [ 2 ]

4 голосов
/ 21 июля 2010

Когда вы вызываете BeginXXX, вы, вероятно, получаете объект IAsyncResult, чтобы вызвать EndXXX, вам нужно передать эту ссылку IAsyncResult в метод.Если вы использовали один и тот же объект из Read и передали его в Write, он не будет работать - в вашем сценарии будут два отдельных IAsyncResult объекта.

Когда я делаю это, я сохраняю ссылку навозвращенный IAsyncResult как локальная переменная класса (если используются обратные вызовы).Когда я звоню EndXXX, я предоставляю эту локальную ссылку (полученную из моего начального BeginXXX) и впоследствии обнуляю ее, чтобы показать, что ее можно использовать повторно.

Обновление 2: , глядя на ваш кодто, что должно быть EndWrite в WriteCallback, на самом деле 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();
        }
    }
}
2 голосов
/ 21 июля 2010

У вас есть следующее:

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

но вы пишете.Разве вы не должны звонить EndWrite?Или я упускаю что-то действительно очевидное?

В этом методе тоже есть ProgressRead();.

...