سؤال

هذا السؤال لديه بالفعل إجابة هنا:

هل هناك طريقة أو طريقة بسيطة لتحويل ملف Stream الى byte[] شركة#؟

هل كانت مفيدة؟

المحلول

استدعاء الوظيفة التالية مثل

byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);

وظيفة:

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; 
            }
        }
    }

نصائح أخرى

الحل الأقصر الذي أعرفه:

using(var memoryStream = new MemoryStream())
{
  sourceStream.CopyTo(memoryStream);
  return memoryStream.ToArray();
}

في .NET Framework 4 والإصدارات الأحدث، Stream الطبقة لديها المدمج في CopyTo الطريقة التي يمكنك استخدامها.

بالنسبة للإصدارات السابقة من إطار العمل، فإن وظيفة المساعدة المفيدة التي يجب توفرها هي:

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);
}

ثم استخدم إحدى الطرق المذكورة أعلاه للنسخ إلى ملف MemoryStream و اتصل 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

يحرر: في الأصل اقترحت استخدام إجابة جيسون لـ أ Stream الذي يدعم Length ملكية.ولكن كان فيه عيب لأنه افترض أن Stream سيعود جميع محتوياته في ملف واحد Read, ، وهذا ليس صحيحًا بالضرورة (وليس لـ a Socket, ، على سبيل المثال.) لا أعرف إذا كان هناك مثال لـ a Stream التنفيذ في BCL الذي يدعم Length ولكن قد تقوم بإرجاع البيانات في أجزاء أقصر مما تطلبه، ولكن يمكن لأي شخص أن يرثها Stream يمكن أن يكون هذا هو الحال بسهولة.

ربما يكون من الأسهل بالنسبة لمعظم الحالات استخدام الحل العام أعلاه، ولكن لنفترض أنك تريد القراءة مباشرةً في مصفوفة موجودة bigEnough:

byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
    offset += r;

وهذا هو، اتصل مرارا وتكرارا Read وحرك الموضع الذي ستخزن فيه البيانات.

    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

أستخدم فئة الامتداد هذه:

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

ما عليك سوى نسخ الفصل إلى الحل الخاص بك ويمكنك استخدامه في كل دفق:

byte[] bytes = myStream.ReadAllBytes()

يعمل بشكل رائع مع جميع عمليات البث الخاصة بي ويوفر الكثير من التعليمات البرمجية!بالطبع يمكنك تعديل هذه الطريقة لاستخدام بعض الأساليب الأخرى هنا لتحسين الأداء إذا لزم الأمر، ولكني أحب أن أبقيها بسيطة.

Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);

حسنًا، ربما أفتقد شيئًا ما هنا، ولكن هذه هي الطريقة التي أفعل بها ذلك:

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;
}

إذا قمت بنشر ملف من جهاز محمول أو غيره

    byte[] fileData = null;
    using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
    {
        fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
    }

تقنية سريعة وقذرة:

    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;
    }

امتحان:

    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); 
    }

أود أن أسأل، لماذا تريد قراءة الدفق إلى بايت[]، إذا كنت ترغب في نسخ محتويات الدفق، فهل لي أن أقترح استخدام MemoryStream وكتابة دفق الإدخال الخاص بك في دفق الذاكرة.

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;
}

من الضروري وجود حل أكثر تعقيدًا قليلاً s.Length يتجاوز Int32.MaxValue.ولكن إذا كنت بحاجة إلى قراءة تدفق كبير جدًا من الذاكرة، فقد ترغب في التفكير في طريقة مختلفة لحل مشكلتك.

يحرر:إذا كان الدفق الخاص بك لا يدعم Length الخاصية، قم بالتعديل باستخدام Earwicker's الحل البديل.

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();

يمكنك أيضًا محاولة القراءة في أجزاء في كل مرة وتوسيع مصفوفة البايت التي يتم إرجاعها:

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" ممتدة بعض الشيء.بالتأكيد، يجب أن يكون المخزن المؤقت "كبيرًا بما فيه الكفاية" ولكن التصميم المناسب للتطبيق يجب أن يتضمن المعاملات والمحددات.في هذا التكوين، سيكون لكل معاملة طول محدد مسبقًا، وبالتالي فإن صفيفك يتوقع عددًا معينًا من البايتات ويدخله في المخزن المؤقت ذي الحجم الصحيح.ستضمن المحددات سلامة المعاملة وسيتم توفيرها داخل كل معاملة.لجعل تطبيقك أفضل، يمكنك استخدام قناتين (مقبسين).يمكن للمرء توصيل معاملات رسائل التحكم ذات الطول الثابت والتي تتضمن معلومات حول الحجم والرقم التسلسلي لمعاملات البيانات التي سيتم نقلها باستخدام قناة البيانات.سوف يقر المتلقي بإنشاء المخزن المؤقت وعندها فقط سيتم إرسال البيانات.إذا لم يكن لديك أي سيطرة على مرسل الدفق فأنت بحاجة إلى مصفوفة متعددة الأبعاد كمخزن مؤقت.ستكون صفائف المكونات صغيرة بما يكفي لتكون قابلة للإدارة وكبيرة بما يكفي لتكون عملية بناءً على تقديرك للبيانات المتوقعة.سيبحث منطق العملية عن محددات البداية المعروفة ثم محددات النهاية في صفائف العناصر اللاحقة.بمجرد العثور على محدد النهاية، سيتم إنشاء مخزن مؤقت جديد لتخزين البيانات ذات الصلة بين المحددات وسيتعين إعادة هيكلة المخزن المؤقت الأولي للسماح بالتخلص من البيانات.

بقدر ما هو رمز لتحويل الدفق إلى صفيف بايت هو واحد أدناه.

Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top