لماذا يتم تالف ملفات .docx عند التنزيل من صفحة ASP.NET؟

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

  •  21-09-2019
  •  | 
  •  

سؤال

لدي هذا الرمز التالي لجلب مرفقات الصفحة إلى المستخدم:

private void GetFile(string package, string filename)
{
    var stream = new MemoryStream();

    try
    {
        using (ZipFile zip = ZipFile.Read(package))
        {
            zip[filename].Extract(stream);
        }
    }
    catch (System.Exception ex)
    {
        throw new Exception("Resources_FileNotFound", ex);
    }

    Response.ClearContent();
    Response.ClearHeaders();
    Response.ContentType = "application/unknown";

    if (filename.EndsWith(".docx"))
    {
        Response.ContentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    }

    Response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
    Response.BinaryWrite(stream.GetBuffer());
    stream.Dispose();
    Response.Flush();
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

تكمن المشكلة في أن جميع الملفات المدعومة تعمل بشكل صحيح (JPG ، GIF ، PNG ، PDF ، DOC ، إلخ) ، ولكن ملفات .docx ، عند تنزيلها ، تالفة وتحتاج إلى إصلاحها من قبل المكتب من أجل فتحها.

في البداية ، لم أكن أعرف ما إذا كانت المشكلة في إلغاء ضغط ملف zip الذي يحتوي على .docx ، لذا بدلاً من وضع ملف الإخراج فقط في الاستجابة ، قمت بحفظه أولاً ، وفتح الملف بنجاح ، لذلك أعرف المشكلة يجب أن يكون في كتابة الاستجابة.

هل تعرف ماذا يمكن أن يحدث؟

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

المحلول

واجهت أيضًا هذه المشكلة ووجدت الجواب هنا: http://www.aspmessageboard.com/showthread.php؟t=230778

اتضح أن تنسيق DOCX يحتاج إلى استجابة. () مباشرة بعد الاستجابة.

نصائح أخرى

عند تخزين ملف ثنائي في SQL Server ، ضع في اعتبارك أن ملفًا مبطنًا لأقرب Word Bouldry ، بحيث يمكنك إضافة بايت إضافي إلى ملف. يتمثل الحل في تخزين حجم الملف الأصلي في DB عند تخزين الملف ، واستخدامه للطول الذي يجب نقله إلى وظيفة الكتابة لكائن الدفق. "Stream.write (Bytes () ، 0 ، طول)". هذه هي الطريقة الوحيدة الموثوقة للحصول على حجم الملف الصحيح ، وهو أمر مهم للغاية بالنسبة للملفات Office 2007 وما فوق ، والتي لا تسمح بأن تكون الأحرف الإضافية في نهايتها (معظم أنواع الملفات الأخرى مثل JPG لا تهتم).

يجب ألا تستخدم stream.GetBuffer() لأنه يعيد صفيف المخزن المؤقت الذي قد يحتوي على بايت غير مستخدمة. يستخدم stream.ToArray() في حين أن. أيضا ، هل حاولت الاتصال stream.Seek(0, SeekOrigin.Begin) قبل كتابة أي شيء؟

مع أطيب التحيات،
أوليفر هانابي

لما يستحق ، واجهت أيضًا نفس المشكلة المدرجة هنا. بالنسبة لي كانت المشكلة في الواقع مع رمز التحميل وليس رمز التنزيل:

    Public Sub ImportStream(FileStream As Stream)
        'Use this method with FileUpload.PostedFile.InputStream as a parameter, for example.
        Dim arrBuffer(FileStream.Length) As Byte
        FileStream.Seek(0, SeekOrigin.Begin)
        FileStream.Read(arrBuffer, 0, FileStream.Length)
        Me.FileImage = arrBuffer
    End Sub

في هذا المثال ، المشكلة هي أنني أعلنت مجموعة البايت arrBuffer مع حجم بايت واحد كبير جدا. ثم يتم حفظ هذه البايت الفارغ مع صورة الملف إلى DB واستنساخها عند التنزيل. سيكون الرمز المصحح:

        Dim arrBuffer(FileStream.Length - 1) As Byte

أيضا للرجوع HttpResponse الكود كما يلي:

                context.Response.Clear()
                context.Response.ClearHeaders()
                'SetContentType() is a function which looks up the correct mime type
                'and also adds and informational header about the lookup process...
                context.Response.ContentType = SetContentType(objPostedFile.FileName, context.Response)
                context.Response.AddHeader("content-disposition", "attachment;filename=" & HttpUtility.UrlPathEncode(objPostedFile.FileName))
                'For reference: Public Property FileImage As Byte()
                context.Response.BinaryWrite(objPostedFile.FileImage)
                context.Response.Flush()

إذا كنت تستخدم النهج أعلاه الذي يستخدم Response.Close () ، فسيقول مديري التنزيل مثل IE10 "لا يمكن تنزيل الملف" لأن أطوال البايت لا تتطابق مع الرؤوس. انظر الوثائق. لا تستخدم الاستجابة. أبدًا. ومع ذلك ، فإن استخدام الفعل المتنافس وحده لا يغلق كتابة البايتات إلى دفق OUPUT ، لذا فإن التطبيقات المستندة إلى XML مثل Word 2007 سترى DOCX تالفة. في هذه الحالة ، كسر القاعدة لعدم استخدام الاستجابة. الكود التالي يحل كلتا المشاكل. قد تختلف نتائجك.

        '*** transfer package file memory buffer to output stream
        Response.ClearContent()
        Response.ClearHeaders()
        Response.AddHeader("content-disposition", "attachment; filename=" + NewDocFileName)
        Me.Response.ContentType = "application/vnd.ms-word.document.12"
        Response.ContentEncoding = System.Text.Encoding.UTF8
        strDocument.Position = 0
        strDocument.WriteTo(Response.OutputStream)
        strDocument.Close()
        Response.Flush()
        'See documentation at http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx
        HttpContext.Current.ApplicationInstance.CompleteRequest() 'This is the preferred method
        'Response.Close() 'BAD pattern. Do not use this approach, will cause 'cannot download file' in IE10 and other download managers that compare content-Header to actual byte count
        Response.End() 'BAD Pattern as well. However, CompleteRequest does not terminate sending bytes, so Word or other XML based appns will see the file as corrupted. So use this to solve it.

Desar: أنت تستخدم Response.close-> هل يمكنك تجربته مع IE 10؟ أراهن أنه لا يعمل (عدد البايت لا تتطابق)

كل شيء يبدو على ما يرام. فكرتي الوحيدة هي محاولة الاتصال بالتخلص من الدفق الخاص بك بعد الاتصال بالاستجابة.

إلقاء نظرة على هذا: كتابة MemoryStream إلى كائن الاستجابة

واجهت نفس المشكلة والحل الوحيد الذي عمل بالنسبة لي هو:

    Response.Clear();
    Response.ContentType = "Application/msword";
    Response.AddHeader("Content-Disposition", "attachment; filename=myfile.docx");
    Response.BinaryWrite(myMemoryStream.ToArray());
    // myMemoryStream.WriteTo(Response.OutputStream); //works too
    Response.Flush();
    Response.Close();
    Response.End();

واجهت نفس المشكلة بينما أحاول فتح مستندات .Docx و .xlsx. أقوم بحل المشكلة عن طريق تحديد قابلية التخزين إلى ServerAndPriven بدلاً من Nocache

هناك طريقتي لاتصال المستند:

public void ProcessRequest(HttpContext context)

 {


       var fi = new FileInfo(context.Request.Path);
        var mediaId = ResolveMediaIdFromName(fi.Name);
        if (mediaId == null) return;

        int mediaContentId;
        if (!int.TryParse(mediaId, out mediaContentId)) return;

        var media = _repository.GetPublicationMediaById(mediaContentId);
        if (media == null) return;

        var fileNameFull = string.Format("{0}{1}", media.Name, media.Extension);
        context.Response.Clear();
        context.Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", fileNameFull));            
        context.Response.Charset = "";
        context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate);
        context.Response.ContentType = media.ContentType;
        context.Response.BinaryWrite(media.Content);
        context.Response.Flush();          
        context.Response.End();          
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top