2010-07-21 5 views
0

J'essaie d'implémenter le mécanisme de notification de progression lors de la copie de fichiers. Je fais cela de la façon suivante:FileStream.EndWrite lève une exception (.NET)

  1. Je crée deux FileStreams - pour la lecture et l'écriture
  2. Appelez le BeginRead passer à un ReadCallback et une structure contenant le flux de lecture et la tableau à remplir avec les données lues dans un fichier.
  3. Dans le ReadCallback j'appelle la méthode EndRead et appeler la méthode BeginWrite sur le flux de fichier utilisé pour l'écriture passant à un WriteCallback et une structure contenant le flux (utilisés pour l'écriture) et le réseau écrire (le même que pour la partie lecture).
  4. Quand j'appelle le EndWrite dans le WriteCallback en lui passant la asyncResult il jette un ArgumentException: Soit l'objet IAsyncResult ne vient pas de la méthode async correspondant sur ce type, ou EndRead a été appelé à plusieurs reprises avec le same IAsyncResult

Aidez-nous à résoudre ce problème.

Mise à jour code source:

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(); 
    } 
} 
+0

Pouvez-vous fournir un échantillon de code s'il vous plaît? –

+0

'EndRead' au lieu de' EndWrite' dans 'WriteCallback', j'ai modifié ma réponse. –

+0

Honte à moi! Adam merci beaucoup pour votre temps précieux passé sur ma question stupide – Niccolo

Répondre

4

Lorsque vous appelez BeginXXX vous donne probablement un objet IAsyncResult, appeler EndXXX vous devez passer cette référence IAsyncResult dans la méthode. Si vous avez utilisé le même objet depuis la lecture et l'avez passé dans l'écriture, cela ne fonctionnera pas - dans votre scénario, il y aura deux objets IAsyncResult distincts.

Lorsque je fais cela, je garde une référence au IAsyncResult retourné en tant que variable de classe locale (si vous utilisez des rappels). Lorsque j'appelle EndXXX, je fournis cette référence locale (obtenue à partir de mon BeginXXX initial) et l'annule par la suite pour indiquer qu'elle peut être réutilisée.

Mise à jour 2: regardant votre code, ce qui devrait être EndWrite dans WriteCallback est en fait une EndRead, erreur de pique-nique :-)

Mise à jour 1: ce qui suit fonctionne très bien pour moi ...

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(); 
     } 
    } 
} 
+0

Je passe un rappel à la méthode BeginWrite et ne récupère pas d'objet IAsyncResult. Le callback a la signature: private void WriteCallback (IAsyncResult asyncResult) et fonctionne sur asyncResult qui lui est passé. (Dans ma paire de lecture (BeginRead - ReadCallback ça marche bien) – Niccolo

+0

Adam, merci pour la réponse Je viens de l'essayer - stocké la référence retournée par le BeginWrite et utilisé dans le rappel au lieu d'être passé en argument. La même exception est renvoyée – Niccolo

+0

'BeginWrite' sur un' Stream' renvoie 'IAsyncResult', mais j'ai oublié la signature de rappel contenue dans le fichier, donc ce n'est pas nécessaire - vous n'avez pas besoin d'utiliser la référence retournée –

2

Vous avez les éléments suivants:

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

mais vous écrivez. Vous ne devriez pas appeler au EndWrite? Ou est-ce que je manque quelque chose de vraiment évident? Il existe également une ProgressRead(); dans cette méthode.

+0

Oui, il devrait y avoir EndWrite Merci, ChrisF – Niccolo

Questions connexes