كيف يمكنني نسخ محتويات تيار واحد إلى آخر ؟

StackOverflow https://stackoverflow.com/questions/230128

  •  04-07-2019
  •  | 
  •  

سؤال

ما هي أفضل طريقة لنسخ محتويات تيار واحد إلى آخر ؟ هل هناك معيار المنفعة طريقة هذا ؟

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

المحلول

من .NET 4.5 على هناك Stream.CopyToAsync طريقة

input.CopyToAsync(output);

هذا سيعود Task التي يمكن أن تستمر على عند الانتهاء مثل:

await input.CopyToAsync(output)

// Code from here on will be run in a continuation.

علما بأن اعتمادا على حيث الدعوة إلى CopyToAsync يتم البرمجية التالي قد أو قد لا يستمر على نفس الموضوع الذي يطلق عليه.

على SynchronizationContext التي تم التقاطها عند الاتصال await سوف تحدد ما موضوع استمرار سيتم تنفيذه على.

بالإضافة إلى ذلك, هذه الدعوة (و هذا هو تنفيذ التفاصيل عرضة للتغيير) لا يزال تسلسل يقرأ ويكتب (فقط لا تضيع المواضيع حظر على إكمال الإدخال/الإخراج).

من .NET 4.0 هناك هو Stream.CopyTo طريقة

input.CopyTo(output);

ل .NET framework 3.5 و قبل

ليس هناك أي شيء خبز في إطار مساعدة مع هذا ؛ لديك لنسخ المحتوى يدويا مثل:

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[32768];
    int read;
    while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write (buffer, 0, read);
    }
}

ملاحظة 1:هذه الطريقة تسمح لك تقرير عن التقدم (x بايت قرأت حتى الآن ...)
ملاحظة 2:لماذا استخدام ثابت حجم المخزن المؤقت وليس input.Length?لأن طول قد لا تكون متاحة!من مستندات:

إذا فئة مشتقة من تيار لا تسعى ، ويدعو إلى الطول ، SetLength, موقف, والسعي ورمي NotSupportedException.

نصائح أخرى

وMemoryStream ديه .WriteTo (outstream)؛

و. NET 4.0 يحتوي .CopyTo على وجوه تيار العادي.

وNET 4.0:

instream.CopyTo(outstream);

وأنا استخدم الطرق الإضافة التالية. لقد الأمثل الزائدة لحين تيار واحد هو MemoryStream.

    public static void CopyTo(this Stream src, Stream dest)
    {
        int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
        byte[] buffer = new byte[size];
        int n;
        do
        {
            n = src.Read(buffer, 0, buffer.Length);
            dest.Write(buffer, 0, n);
        } while (n != 0);           
    }

    public static void CopyTo(this MemoryStream src, Stream dest)
    {
        dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
    }

    public static void CopyTo(this Stream src, MemoryStream dest)
    {
        if (src.CanSeek)
        {
            int pos = (int)dest.Position;
            int length = (int)(src.Length - src.Position) + pos;
            dest.SetLength(length); 

            while(pos < length)                
                pos += src.Read(dest.GetBuffer(), pos, length - pos);
        }
        else
            src.CopyTo((Stream)dest);
    }

الأسئلة الأساسية التي تميز تطبيقات "CopyStream" هي:

  • حجم القراءة العازلة
  • حجم يكتب
  • يمكن أن نستخدم أكثر من مؤشر ترابط واحد (الكتابة حين نقرأ).

الإجابات على هذه الأسئلة تؤدي إلى حد كبير تطبيقات مختلفة من CopyStream و تعتمد على أي نوع من تيارات لديك و ما كنت تحاول تحسين."أفضل" التنفيذ تحتاج حتى إلى معرفة ما محددة الأجهزة تيارات كانت القراءة والكتابة.

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

public static void CopyStream(Stream input, Stream output)
{
  using (StreamReader reader = new StreamReader(input))
  using (StreamWriter writer = new StreamWriter(output))
  {
    writer.Write(reader.ReadToEnd());
  }
}

ملاحظة: قد يكون هناك أيضا بعض القضايا المتعلقة بالبيانات وحرف ترميزات الثنائية

والإطار الصافي 4 إدخال طريقة جديدة "CopyTo لل" من تيار فئة من System.IO مساحة الاسم. باستخدام هذه الطريقة يمكننا نسخ تيار واحد للتيار آخر من فئة دفق مختلفة.

وهنا مثال لذلك.

    FileStream objFileStream = File.Open(Server.MapPath("TextFile.txt"), FileMode.Open);
    Response.Write(string.Format("FileStream Content length: {0}", objFileStream.Length.ToString()));

    MemoryStream objMemoryStream = new MemoryStream();

    // Copy File Stream to Memory Stream using CopyTo method
    objFileStream.CopyTo(objMemoryStream);
    Response.Write("<br/><br/>");
    Response.Write(string.Format("MemoryStream Content length: {0}", objMemoryStream.Length.ToString()));
    Response.Write("<br/><br/>");

ولسوء الحظ، ليس هناك حل بسيط حقا. يمكنك أن تجرب شيئا من هذا القبيل:

Stream s1, s2;
byte[] buffer = new byte[4096];
int bytesRead = 0;
while (bytesRead = s1.Read(buffer, 0, buffer.Length) > 0) s2.Write(buffer, 0, bytesRead);
s1.Close(); s2.Close();

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

ودائما التحقق من الوثائق من فئة دفق المحددة التي تستخدم قبل استخدام حل عام.

قد يكون هناك طريقة للقيام بذلك بشكل أكثر كفاءة، وهذا يتوقف على نوع من تيار كنت تعمل مع. إذا يمكنك تحويل واحد أو كلا من تيارات الخاص بك إلى MemoryStream، يمكنك استخدام الأسلوب GetBuffer للعمل مباشرة مع مجموعة بايت تمثيل البيانات الخاصة بك. هذا يتيح لك استخدام أساليب مثل Array.CopyTo، الذي مجردة بعيدا عن القضايا التي أثارها fryguybob. يمكنك فقط الثقة .NET لمعرفة الطريقة المثلى لنسخ البيانات.

وإذا كنت ترغب في عبارة procédure نسخ تيار الآخر أن نيك نشرت على ما يرام ولكن أنه يفتقد إعادة الموقف، ينبغي أن يكون

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[32768];
    long TempPos = input.Position;
    while (true)    
    {
        int read = input.Read (buffer, 0, buffer.Length);
        if (read <= 0)
            return;
        output.Write (buffer, 0, read);
    }
    input.Position = TempPos;// or you make Position = 0 to set it at the start
}

ولكن ليس إذا كان في وقت التشغيل باستخدام الإجراء الذي shpuld استخدام تيار الذاكرة

Stream output = new MemoryStream();
byte[] buffer = new byte[32768]; // or you specify the size you want of your buffer
long TempPos = input.Position;
while (true)    
{
    int read = input.Read (buffer, 0, buffer.Length);
    if (read <= 0)
        return;
    output.Write (buffer, 0, read);
 }
    input.Position = TempPos;// or you make Position = 0 to set it at the start

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

const int BUFFER_SIZE = 4096;

static byte[] bufferForRead = new byte[BUFFER_SIZE];
static byte[] bufferForWrite = new byte[BUFFER_SIZE];

static Stream sourceStream = new MemoryStream();
static Stream destinationStream = new MemoryStream();

static void Main(string[] args)
{
    // Initial read from source stream
    sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}

private static void BeginReadCallback(IAsyncResult asyncRes)
{
    // Finish reading from source stream
    int bytesRead = sourceStream.EndRead(asyncRes);
    // Make a copy of the buffer as we'll start another read immediately
    Array.Copy(bufferForRead, 0, bufferForWrite, 0, bytesRead);
    // Write copied buffer to destination stream
    destinationStream.BeginWrite(bufferForWrite, 0, bytesRead, BeginWriteCallback, null);
    // Start the next read (looks like async recursion I guess)
    sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}

private static void BeginWriteCallback(IAsyncResult asyncRes)
{
    // Finish writing to destination stream
    destinationStream.EndWrite(asyncRes);
}

لالصافي 3.5 وقبل محاولة:

MemoryStream1.WriteTo(MemoryStream2);

وسهلة وآمنة - جعل تيار جديد من المصدر الأصلي:

    MemoryStream source = new MemoryStream(byteArray);
    MemoryStream copy = new MemoryStream(byteArray);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top