[c#] كيف يمكنني حفظ دفق إلى ملف في C #؟


3 Answers

يجب عدم استخدام StreamReader للملفات الثنائية (مثل gifs أو jpgs). StreamReader هو بيانات النص . من المؤكد أنك ستفقد البيانات إذا استخدمتها لبيانات ثنائية عشوائية. (إذا كنت تستخدم Encoding.GetEncoding (28591) ، فربما تكون بخير ، ولكن ما هي الفائدة؟)

لماذا تحتاج إلى استخدام StreamReader على الإطلاق؟ لماذا لا نحتفظ فقط بالبيانات الثنائية كبيانات ثنائية ونكتبها مرة أخرى إلى القرص (أو SQL) كبيانات ثنائية؟

تعديل: حيث يبدو أن هذا أمر يريد الناس رؤيته ... إذا كنت تريد فقط نسخ دفق واحد إلى آخر (على سبيل المثال إلى ملف) ، استخدم شيئًا مثل هذا:

/// <summary>
/// Copies the contents of input to output. Doesn't close either stream.
/// </summary>
public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8 * 1024];
    int len;
    while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, len);
    }    
}

لاستخدامها في تفريغ دفق إلى ملف ، على سبيل المثال:

using (Stream file = File.Create(filename))
{
    CopyStream(input, file);
}

لاحظ أن Stream.CopyTo قد تم تقديمه في .NET 4 ، Stream.CopyTo أساسًا نفس الغرض.

Question

لدي كائن StreamReader الذي قمت بتهيئةه مع دفق ، والآن أريد حفظ هذا الدفق على القرص (قد يكون الدفق .gif أو .jpg أو .pdf ).

الكود الموجود:

StreamReader sr = new StreamReader(myOtherObject.InputStream);
  1. أحتاج إلى حفظ هذا على القرص (لدي اسم الملف).
  2. في المستقبل قد أرغب في تخزين هذا إلى SQL Server.

لدي نوع الترميز أيضاً ، والذي سأحتاجه إذا قمت بتخزينه إلى SQL Server ، صحيح؟




لا أحصل على جميع الإجابات باستخدام CopyTo ، حيث ربما لم تتم ترقية الأنظمة التي تستخدم التطبيق إلى .NET 4.0+. أعلم أن البعض يرغب في إجبار الناس على الترقية ، لكن التوافق أيضًا لطيف أيضًا.

شيء آخر ، لا أستخدم تدفقًا لنسخه من بث آخر في المقام الأول. لماذا لا تفعل فقط:

byte[] bytes = myOtherObject.InputStream.ToArray();

بمجرد الحصول على البايت ، يمكنك بسهولة كتابتها إلى ملف:

public static void WriteFile(string fileName, byte[] bytes)
{
    string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (!path.EndsWith(@"\")) path += @"\";

    if (File.Exists(Path.Combine(path, fileName)))
        File.Delete(Path.Combine(path, fileName));

    using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write)
    {
        fs.Write(bytes, 0, (int)bytes.Length);
        fs.Close();
    }
}

يعمل هذا الكود كما قمت باختباره مع ملف .jpg ، على الرغم من أنني أعترف بأنني استخدمته فقط مع ملفات صغيرة (أقل من 1 ميجابايت). دفق واحد ، لا نسخ بين تدفقات ، لا ترميز مطلوب ، فقط اكتب البايت! لا حاجة إلى زيادة تعقيد الأمور مع StreamReader إذا كان لديك بالفعل دفق يمكنك التحويل إلى bytes مباشرة مع .ToArray() !

فقط السلبيات المحتملة التي يمكنني رؤيتها في القيام بها بهذه الطريقة هي إذا كان هناك ملف كبير لديك ، يكون بمثابة دفق واستخدام .CopyTo() أو مكافئ يسمح لـ FileStream .CopyTo() بدلاً من استخدام صفيف البايت وقراءة البايتات واحد بواسطة واحدة. قد يكون أبطأ القيام بذلك بهذه الطريقة ، نتيجة لذلك. ولكن لا يجب أن تختنق نظرًا لأن أسلوب .Write() في التعامل مع FileStream بكتابة البايتات ، ولا يفعل ذلك سوى بايت واحد في كل مرة ، لذا لن يؤدي إلى إعاقة الذاكرة ، باستثناء أنه سيكون لديك ذاكرة كافية استمر في الدفق ككائن byte[] . في وضعي حيث استخدمت هذا ، في الحصول على OracleBlob ، كان عليّ أن أذهب إلى byte[] ، وكان صغيرًا بما فيه الكفاية ، وبالإضافة إلى ذلك ، لم يكن هناك أي تدفق متاح لي ، على أي حال ، لذلك أرسلت للتو وحدات البايت الخاصة بي إلى وظيفتي ، في الاعلى.

خيار آخر ، باستخدام دفق ، سيكون استخدامه مع وظيفة CopyStream الخاصة بـ Jon Skeet والتي كانت في وظيفة أخرى - وهذا يستخدم FileStream فقط لنقل مسار الإدخال وإنشاء الملف منه مباشرة. لا يستخدم File.Create ، كما فعل (والتي بدت في البداية مشكلة بالنسبة لي ، ولكن وجدت في وقت لاحق أنه من المرجح مجرد خلل VS ...).

/// <summary>
/// Copies the contents of input to output. Doesn't close either stream.
/// </summary>
public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8 * 1024];
    int len;
    while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, len);
    }    
}

public static void WriteFile(string fileName, Stream inputStream)
{
    string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (!path.EndsWith(@"\")) path += @"\";

    if (File.Exists(Path.Combine(path, fileName)))
        File.Delete(Path.Combine(path, fileName));

    using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write)
    {
        CopyStream(inputStream, fs);
    }

    inputStream.Close();
    inputStream.Flush();
}



private void SaveFileStream(String path, Stream stream)
{
    var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write);
    stream.CopyTo(fileStream);
    fileStream.Dispose();
}



لماذا لا تستخدم كائن FileStream؟

public void SaveStreamToFile(string fileFullPath, Stream stream)
{
    if (stream.Length == 0) return;

    // Create a FileStream object to write a stream to a file
    using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
    {
        // Fill the bytes[] array with the stream data
        byte[] bytesInStream = new byte[stream.Length];
        stream.Read(bytesInStream, 0, (int)bytesInStream.Length);

        // Use FileStream object to write to the specified file
        fileStream.Write(bytesInStream, 0, bytesInStream.Length);
     }
}



Related