Quelle est la méthode préférée pour créer un tableau d'octets à partir d'un flux d'entrée?
Voici ma solution actuelle avec .NET 3.5.
Stream s;
byte[] b;
using (BinaryReader br = new BinaryReader(s))
{
b = br.ReadBytes((int)s.Length);
}
Est-ce toujours une meilleure idée de lire et d'écrire des morceaux du flux?
Réponses:
Cela dépend vraiment de votre confiance
s.Length
. Pour de nombreux flux, vous ne savez tout simplement pas combien de données il y aura. Dans de tels cas - et avant .NET 4 - j'utiliserais du code comme ceci:Avec .NET 4 et supérieur, j'utiliserais
Stream.CopyTo
, ce qui est fondamentalement équivalent à la boucle dans mon code - créez leMemoryStream
, appelezstream.CopyTo(ms)
puis revenezms.ToArray()
. Travail accompli.Je devrais peut-être expliquer pourquoi ma réponse est plus longue que les autres.
Stream.Read
ne garantit pas qu'il lira tout ce qu'il a demandé. Si vous lisez un flux réseau, par exemple, il peut lire la valeur d'un paquet puis revenir, même s'il y aura bientôt plus de données.BinaryReader.Read
continuera jusqu'à la fin du flux ou à votre taille spécifiée, mais vous devez toujours connaître la taille pour commencer.La méthode ci-dessus continuera à lire (et à copier dans a
MemoryStream
) jusqu'à ce qu'il n'y ait plus de données. Il demande ensuite àMemoryStream
de renvoyer une copie des données dans un tableau. Si vous connaissez la taille pour commencer - ou pensez que vous connaissez la taille, sans être sûr - vous pouvez construire laMemoryStream
taille pour commencer. De même, vous pouvez mettre un chèque à la fin, et si la longueur du flux est de la même taille que le tampon (renvoyé parMemoryStream.GetBuffer
), vous pouvez simplement retourner le tampon. Le code ci-dessus n'est donc pas tout à fait optimisé, mais sera au moins correct. Il n'assume aucune responsabilité pour la fermeture du flux - l'appelant devrait le faire.Consultez cet article pour plus d'informations (et une implémentation alternative).
la source
16*1024
spécifiquement?Bien que la réponse de Jon soit correcte, il réécrit du code qui existe déjà dans
CopyTo
. Donc, pour .Net 4, utilisez la solution de Sandip, mais pour la version précédente de .Net, utilisez la réponse de Jon. Le code de Sandip serait amélioré en utilisant «using», car dansCopyTo
de nombreuses situations, les exceptions sont très probables et ne le laisseraientMemoryStream
pas de côté.la source
input
existe déjà unMemorySteam
court-circuit. Je sais que ce serait stupide de la part de l'appelant de passer unMemoryStream
mais ...MemoryStream
savoir si l'optimisation est logique dans votre contexte, c'est la comparaison du temps nécessaire pour effectuer des millions de conversions de type par rapport au temps nécessaire pour copier celui qui estMemoryStream
dans un autreMemoryStream
.Je veux juste souligner que si vous avez un MemoryStream, vous en avez déjà
memorystream.ToArray()
.De plus, si vous avez affaire à des flux de sous-types inconnus ou différents et que vous pouvez en recevoir un
MemoryStream
, vous pouvez relayer cette méthode pour ces cas et toujours utiliser la réponse acceptée pour les autres, comme ceci:la source
MemoryStream
s. Bien sûr, l'exemple est également manifestement incomplet, dans la façon dont il utilise une variable non initialisée.stream.Seek(1L, SeekOrigin.Begin)
, avant d'appeler en lecture, si le flux est un flux de mémoire, vous obtiendrez 1 octet de plus que s'il s'agit d'un autre flux. Si l'appelant s'attend à lire depuis la position actuelle jusqu'à la fin du flux, vous ne devez pas utiliserCopyTo
ouToArray()
; Dans la plupart des cas, ce ne sera pas un problème, mais si l'appelant ne connaît pas ce comportement excentrique, il sera confus.la source
juste mes quelques cents ... la pratique que j'utilise souvent est d'organiser les méthodes comme celle-ci en tant qu'assistant personnalisé
ajouter un espace de noms au fichier de configuration et l'utiliser où vous le souhaitez
la source
CopyTo
n'était pas disponibleStream
avant 4.0.Vous pouvez simplement utiliser la méthode ToArray () de la classe MemoryStream, par exemple
la source
Vous pouvez même le rendre plus sophistiqué avec des extensions:
Et puis appelez-le comme une méthode régulière:
la source
J'obtiens une erreur de compilation avec le code de Bob (c'est-à-dire le questionneur). Stream.Length est long tandis que BinaryReader.ReadBytes prend un paramètre entier. Dans mon cas, je ne m'attends pas à traiter des flux suffisamment grands pour nécessiter une longue précision, j'utilise donc les éléments suivants:
la source
Si quelqu'un l'aime, voici une seule solution .NET 4+ formée comme une méthode d'extension sans l'appel inutile Dispose sur le MemoryStream. Il s'agit d'une optimisation désespérément triviale, mais il convient de noter que l'échec de l'élimination d'un MemoryStream n'est pas un véritable échec.
la source
Celui ci-dessus est correct ... mais vous rencontrerez une corruption de données lorsque vous envoyez des trucs via SMTP (si vous en avez besoin). J'ai changé pour quelque chose d'autre qui aidera à envoyer correctement octet par octet: '
la source
Créez une classe d'assistance et référencez-la partout où vous souhaitez l'utiliser.
la source
Dans l'espace de noms RestSharp.Extensions, il y a la méthode ReadAsBytes. À l'intérieur de cette méthode est utilisé MemoryStream et il y a le même code que dans certains exemples sur cette page, mais lorsque vous utilisez RestSharp, c'est la manière la plus simple.
la source
Vous pouvez utiliser cette méthode d'extension.
la source
C'est la fonction que j'utilise, testée et qui a bien fonctionné. veuillez garder à l'esprit que 'input' ne doit pas être nul et 'input.position' doit être réinitialisé à '0' avant de lire sinon cela rompra la boucle de lecture et rien ne lira pour être converti en tableau.
la source
la source
j'ai pu le faire fonctionner sur une seule ligne:
comme clarifié par johnnyRose , le code ci-dessus ne fonctionnera que pour MemoryStream
la source
localStream
n'est pas unMemoryStream
? Ce code échouera.localStream
à unMemoryStream
, maislocalStream
est pas unMemoryStream
, il va échouer. Ce code se compilera correctement, mais il pourrait échouer lors de l'exécution, selon le type réel delocalStream
. Vous ne pouvez pas toujours convertir arbitrairement un type de base en type enfant; en savoir plus ici . Ceci est un autre bon exemple qui explique pourquoi vous ne pouvez pas toujours faire cela.