Ответ 1
Я также столкнулся с этой проблемой и на самом деле нашел ответ здесь: http://www.aspmessageboard.com/showthread.php?t=230778
Оказывается, формат docx должен иметь Response.End() сразу после Response.BinaryWrite.
У меня есть следующий код для вставки вложений страницы пользователю:
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 при загрузке повреждены, и они должны быть исправлены Office для их открытия.
Сначала я не знал, была ли проблема при распаковке zip файла, содержащего .docx, поэтому вместо того, чтобы помещать выходной файл только в ответ, я сначала сохранил его, и файл был успешно открыт, поэтому я знаете, проблема должна быть при написании ответа.
Знаете ли вы, что может случиться?
Я также столкнулся с этой проблемой и на самом деле нашел ответ здесь: http://www.aspmessageboard.com/showthread.php?t=230778
Оказывается, формат docx должен иметь Response.End() сразу после Response.BinaryWrite.
При хранении двоичного файла в SQL Server помните, что файл дополняется к ближайшей границе слова, поэтому у вас может быть добавлен дополнительный байт, добавленный в файл. Решение состоит в том, чтобы сохранить исходный размер файла в db при сохранении файла и использовать его для длины, которая должна быть передана функции записи объекта Stream. "Stream.Write(байты(), 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
с размером одного байта слишком большим. Этот нулевой байт затем сохраняется вместе с файловым изображением в БД и воспроизводится при загрузке. Исправленный код:
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, скажут: "Не удается загрузить файл", потому что длина байтов не соответствует заголовкам. См. Документацию. НЕ используйте response.Close. КОГДА-ЛИБО. Однако, используя только глагол CompeteRequest, он не отключает запись байтов в поток вывода, поэтому приложения на основе XML, такие как WORD 2007, будут видеть, что docx поврежден. В этом случае нарушите правило, чтобы НИКОГДА не использовалось Response.End. Следующий код решает обе проблемы. Ваши результаты могут отличаться.
'*** 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.
@Cesar: вы используете response.Close → можете ли вы попробовать его с IE 10? ставка не работает (количество байт не совпадает)
Все выглядит нормально. Моя единственная идея - попытаться вызвать Dispose в вашем потоке после вызова Response.Flush вместо ранее, на всякий случай, если байты не полностью записаны до сброса.
Взгляните на это: Написание 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. Я решаю проблему, определяя кешируемость ServerAndPrivate вместо 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();
}