web-dev-qa-db-fra.com

Renvoyer un flux depuis File.OpenRead ()

Je suis en train d'écrire un service WCF qui permettra à un site Web ASP.Net de récupérer des fichiers (basé sur cet article ). Mon problème est que lorsque je retourne le flux, il est vide.

Pour des raisons de simplicité, j'ai isolé le code dans une application Winforms simple pour essayer de trouver le problème du retour d'un flux. Voici le code:

    private Stream TestStream()
    {
        Stream fs = File.OpenRead(@"c:\testdocument.docx");
        return fs;
    }

    // This method converts the filestream into a byte array so that when it is 
    // used in my ASP.Net project the file can be sent using response.Write
    private void Test()
    {            
        System.IO.MemoryStream data = new System.IO.MemoryStream();
        System.IO.Stream str = TestStream();

        str.CopyTo(data);
        byte[] buf = new byte[data.Length];
        data.Read(buf, 0, buf.Length);                       
    }

Le résultat de ce code est que buf a une longueur de 12 587 octets (la longueur correcte du fichier), mais il ne contient que des 0.

Le document Word s'ouvre sans problèmes si j'essaie. Est-ce qu'il me manque quelque chose d'évident?

48
GrandMasterFlush

Vous avez oublié de chercher:

str.CopyTo(data);
data.Seek(0, SeekOrigin.Begin); // <-- missing line
byte[] buf = new byte[data.Length];
data.Read(buf, 0, buf.Length);
39
ken2k

Options:

  • Utilisation data.Seek comme suggéré par ken2k
  • Utilisez la propriété un peu plus simple Position:

    data.Position = 0;
    
  • Utilisez l’appel ToArray dans MemoryStream pour vous simplifier la vie:

    byte[] buf = data.ToArray();
    

La troisième option serait mon approche préférée.

Notez que vous devriez avoir une instruction using pour fermer le flux de fichiers automatiquement (et éventuellement pour MemoryStream), et j'ajouterais une directive using pour System.IO pour rendre votre code plus propre:

byte[] buf;
using (MemoryStream data = new MemoryStream())
{
    using (Stream file = TestStream())
    {
        file.CopyTo(data);
        buf = data.ToArray();
    }
}

// Use buf

Vous pouvez également créer une méthode d’extension sur Stream pour le faire pour vous au même endroit, par exemple.

public static byte[] CopyToArray(this Stream input)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        input.CopyTo(memoryStream);
        return memoryStream.ToArray();
    }
}

Notez que cela ne ferme pas le flux d'entrée .

15
Jon Skeet

Vous avez oublié de réinitialiser la position du flux de mémoire:

private void Test()
{            
    System.IO.MemoryStream data = new System.IO.MemoryStream();
    System.IO.Stream str = TestStream();

    str.CopyTo(data);
    // Reset memory stream
    data.Seek(0, SeekOrigin.Begin);
    byte[] buf = new byte[data.Length];
    data.Read(buf, 0, buf.Length);                       
}

Mise à jour:

Une dernière chose à noter: il est généralement préférable de ne pas ignorer les valeurs de retour des méthodes. Une implémentation plus robuste devrait vérifier le nombre d'octets lus après le retour de l'appel:

private void Test()
{            
    using(MemoryStream data = new MemoryStream())
    {
        using(Stream str = TestStream())
        {
           str.CopyTo(data);
        }
        // Reset memory stream
        data.Seek(0, SeekOrigin.Begin);
        byte[] buf = new byte[data.Length];
        int bytesRead = data.Read(buf, 0, buf.Length);

        Debug.Assert(bytesRead == data.Length, 
                    String.Format("Expected to read {0} bytes, but read {1}.",
                        data.Length, bytesRead));
    }                     
}
5
afrischke

Vous avez besoin

    str.CopyTo(data);
    data.Position = 0; // reset to beginning
    byte[] buf = new byte[data.Length];
    data.Read(buf, 0, buf.Length);  

Et puisque votre méthode Test() imite le client, elle doit Close() ou Dispose() le str Stream. Et le memoryStream aussi, à peine sorti du principal.

3
Henk Holterman

Essayez de changer votre code pour ceci:

private void Test()
{            
    System.IO.MemoryStream data = new System.IO.MemoryStream(TestStream());

    byte[] buf = new byte[data.Length];
    data.Read(buf, 0, buf.Length);                       
}
1
ilivewithian