Existe-t-il un moyen simple ou une méthode pour convertir une Stream
en un byte[]
en C #?
Appelle la fonction suivante comme
byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);
Une fonction:
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0;
if(stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if(stream.CanSeek)
{
stream.Position = originalPosition;
}
}
}
La solution la plus courte que je connaisse:
using(var memoryStream = new MemoryStream())
{
sourceStream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
Dans .NET Framework 4 et versions ultérieures, la classe Stream
a une méthode intégrée CopyTo
que vous pouvez utiliser.
Pour les versions précédentes du framework, la fonction d'aide pratique à avoir est la suivante:
public static void CopyStream(Stream input, Stream output)
{
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0)
output.Write(b, 0, r);
}
Utilisez ensuite l’une des méthodes ci-dessus pour copier sur une MemoryStream
et appelez GetBuffer
:
var file = new FileStream("c:\\foo.txt", FileMode.Open);
var mem = new MemoryStream();
// If using .NET 4 or later:
file.CopyTo(mem);
// Otherwise:
CopyStream(file, mem);
// getting the internal buffer (no additional copying)
byte[] buffer = mem.GetBuffer();
long length = mem.Length; // the actual length of the data
// (the array may be longer)
// if you need the array to be exactly as long as the data
byte[] truncated = mem.ToArray(); // makes another copy
Edit: À l'origine, j'ai suggéré d'utiliser la réponse de Jason pour un Stream
qui prend en charge la propriété Length
. Mais il avait un défaut car il supposait que la Stream
renverrait tout son contenu dans un seul Read
, ce qui n'est pas nécessairement vrai (pas pour un Socket
, par exemple.) 'sais pas s'il existe un exemple d'implémentation Stream
dans la BCL qui prend en charge Length
mais qui peut renvoyer les données en morceaux plus courts que ceux demandés, mais n'importe qui peut hériter de Stream
this pourrait facilement être le cas.
Il est probablement plus simple d'utiliser la solution générale ci-dessus dans la plupart des cas, mais supposons que vous vouliez lire directement dans un tableau qui est bigEnough
:
byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
offset += r;
En d'autres termes, appelez à plusieurs reprises Read
et déplacez la position dans laquelle vous souhaitez stocker les données.
byte[] buf; // byte array
Stream stream=Page.Request.InputStream; //initialise new stream
buf = new byte[stream.Length]; //declare arraysize
stream.Read(buf, 0, buf.Length); // read from stream to byte array
J'utilise cette classe d'extension:
public static class StreamExtensions
{
public static byte[] ReadAllBytes(this Stream instream)
{
if (instream is MemoryStream)
return ((MemoryStream) instream).ToArray();
using (var memoryStream = new MemoryStream())
{
instream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
}
Copiez simplement la classe dans votre solution et vous pourrez l'utiliser sur tous les flux:
byte[] bytes = myStream.ReadAllBytes()
Fonctionne très bien pour tous mes flux et enregistre beaucoup de code! Bien sûr, vous pouvez modifier cette méthode pour utiliser certaines des autres approches afin d’améliorer les performances si nécessaire, mais j’aime rester simple.
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
Ok, peut-être que quelque chose me manque, mais voici comment je le fais:
public static Byte[] ToByteArray(this Stream stream) {
Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length);
Byte[] buffer = new Byte[length];
stream.Read(buffer, 0, length);
return buffer;
}
si vous postez un fichier depuis un appareil mobile ou un autre
byte[] fileData = null;
using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
{
fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
}
Stream s;
int len = (int)s.Length;
byte[] b = new byte[len];
int pos = 0;
while((r = s.Read(b, pos, len - pos)) > 0) {
pos += r;
}
Une solution légèrement plus compliquée est nécessaire si s.Length
dépasse Int32.MaxValue
. Toutefois, si vous devez lire un flux aussi volumineux en mémoire, vous pouvez envisager une approche différente de votre problème.
Edit: Si votre flux ne prend pas en charge la propriété Length
, modifiez-le à l'aide d'Earwicker solution de contournement .
public static class StreamExtensions {
// Credit to Earwicker
public static void CopyStream(this Stream input, Stream output) {
byte[] b = new byte[32768];
int r;
while ((r = input.Read(b, 0, b.Length)) > 0) {
output.Write(b, 0, r);
}
}
}
[...]
Stream s;
MemoryStream ms = new MemoryStream();
s.CopyStream(ms);
byte[] b = ms.GetBuffer();
Technique rapide et sale:
static byte[] StreamToByteArray(Stream inputStream)
{
if (!inputStream.CanRead)
{
throw new ArgumentException();
}
// This is optional
if (inputStream.CanSeek)
{
inputStream.Seek(0, SeekOrigin.Begin);
}
byte[] output = new byte[inputStream.Length];
int bytesRead = inputStream.Read(output, 0, output.Length);
Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
return output;
}
Tester:
static void Main(string[] args)
{
byte[] data;
string path = @"C:\Windows\System32\notepad.exe";
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
{
data = StreamToByteArray(fs);
}
Debug.Assert(data.Length > 0);
Debug.Assert(new FileInfo(path).Length == data.Length);
}
Je voudrais demander, pourquoi voulez-vous lire un flux dans un octet [], si vous souhaitez copier le contenu d'un flux, puis-je suggérer d'utiliser MemoryStream et d'écrire votre flux d'entrée dans un flux de mémoire.
Vous pouvez également essayer de lire des parties à la fois et d’élargir le tableau d’octets renvoyé:
public byte[] StreamToByteArray(string fileName)
{
byte[] total_stream = new byte[0];
using (Stream input = File.Open(fileName, FileMode.Open, FileAccess.Read))
{
byte[] stream_array = new byte[0];
// Setup whatever read size you want (small here for testing)
byte[] buffer = new byte[32];// * 1024];
int read = 0;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
stream_array = new byte[total_stream.Length + read];
total_stream.CopyTo(stream_array, 0);
Array.Copy(buffer, 0, stream_array, total_stream.Length, read);
total_stream = stream_array;
}
}
return total_stream;
}
"bigEnough" tableau est un peu exagéré. Bien sûr, la mémoire tampon doit être "volumineuse", mais la conception correcte d'une application doit inclure des transactions et des délimiteurs. Dans cette configuration, chaque transaction aurait une longueur prédéfinie, ainsi votre tableau anticiperait un certain nombre d'octets et l'insérerait dans un tampon correctement dimensionné. Les délimiteurs assureraient l'intégrité de la transaction et seraient fournis dans chaque transaction. Pour améliorer encore votre application, vous pouvez utiliser 2 canaux (2 sockets). L’un communiquerait des transactions de messages de contrôle de longueur fixe qui incluraient des informations sur la taille et le numéro de séquence de la transaction de données à transférer par le canal de données. Le destinataire accuserait réception de la création de la mémoire tampon et les données ne seraient alors envoyées. Si vous n'avez aucun contrôle sur l'expéditeur du flux, vous avez besoin d'un tableau multidimensionnel en tant que tampon. Les matrices de composants seraient suffisamment petites pour être gérables et suffisamment grandes pour être pratiques, en fonction de votre estimation des données attendues. La logique du processus recherche les délimiteurs de début connus, puis les délimiteurs de fin dans les tableaux d'éléments suivants. Une fois que le délimiteur final est trouvé, un nouveau tampon sera créé pour stocker les données pertinentes entre les délimiteurs et le tampon initial devra être restructuré pour permettre la suppression des données.
En ce qui concerne le code pour convertir un flux en tableau d'octets, il en est un ci-dessous.
Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);