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?
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);
Options:
data.Seek
comme suggéré par ken2kUtilisez 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 .
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));
}
}
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.
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);
}