Pourquoi les fichiers .docx être corrompus lors du téléchargement d'une page ASP.NET?

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

  •  21-09-2019
  •  | 
  •  

Question

Je le code ci-dessous pour apporter des pièces jointes de page à l'utilisateur:

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

Le problème est que tous les fichiers pris en charge fonctionne correctement (jpg, gif, png, pdf, doc, etc.), mais les fichiers .docx, lorsque téléchargé, sont corrompus et ils doivent être fixés par le Bureau pour être ouvert.

Au début, je ne savais pas si le problème était décompressé le fichier zip contenant le .docx, donc au lieu de mettre le fichier de sortie que dans la réponse, je l'ai enregistré en premier lieu, et le fichier ouvert avec succès, alors je connaître le problème devrait être à l'écriture de réponse.

Savez-vous ce qui peut se passer?

Était-ce utile?

La solution

J'ai aussi rencontré ce problème et trouvé en fait la réponse ici: http: // www .aspmessageboard.com / showthread.php? t = 230778

Il se trouve que le format docx doit avoir Response.End () juste après la Response.BinaryWrite.

Autres conseils

Lors de la mémorisation d'un fichier binaire dans SQL Server, gardez à l'esprit qu'un fichier est rembourré au boundry mot le plus proche, vous pouvez éventuellement avoir un octet supplémentaire ajouté à un fichier. La solution est de stocker la taille du fichier d'origine dans la db lorsque vous enregistrez le fichier, et l'utiliser pour la longueur qui doit être transmise à la fonction d'écriture de l'objet Stream. "Stream.Write (octets (), 0, longueur)". Ceci est la seule façon fiable d'obtenir la taille de fichier correct, ce qui est très important pour Office 2007 et des fichiers, qui ne permettent pas de caractères supplémentaires d'être sur la fin d'entre eux (la plupart des autres types de fichiers tels que jpg ne se soucient pas).

Vous ne devriez pas utiliser stream.GetBuffer() car il retourne le tableau de tampon qui peut contenir des octets inutilisés. Utilisez plutôt stream.ToArray(). Aussi, avez-vous essayé d'appeler stream.Seek(0, SeekOrigin.Begin) avant d'écrire quoi que ce soit?

Cordialement,
Oliver Hanappi

Pour ce que ça vaut, j'ai aussi rencontré le même problème répertorié. Pour moi, la question était en fait avec le code de téléchargement et non le code de téléchargement:

    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

Dans cet exemple, le problème est que je déclare le tableau d'octets arrBuffer avec une taille d'un octet trop grand. Cet octet nul est alors enregistré avec l'image de fichier à la DB et reproduit le téléchargement. Le code corrigé serait:

        Dim arrBuffer(FileStream.Length - 1) As Byte

Aussi pour référence mon code HttpResponse se présente comme suit:

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

Si vous utilisez l'approche ci-dessus qui utilise response.Close (), les gestionnaires de téléchargement tels que IE10 diront « ne peut pas télécharger le fichier » car la longueur des octets ne correspondent pas à les en-têtes. Consultez la documentation. Ne pas utiliser response.Close. DÉJÀ. Cependant, en utilisant le verbe CompeteRequest ne se ferme pas seul à l'écriture d'octets dans le flux de ouput si des applications basées sur XML tels que Word 2007 verront le docx comme corrompu. Dans ce cas, briser la règle de ne JAMAIS utiliser Response.End. Le code suivant résout les deux problèmes. Vos résultats peuvent varier.

        '*** 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: vous utilisez response.Close -> vous pouvez l'essayer avec IE 10? parier qu'il ne fonctionne pas (le nombre d'octets ne correspondent pas)

Tout semble ok. Ma seule idée est d'essayer d'appeler Dispose sur votre flux après avoir appelé Response.Flush au lieu d'avant, juste au cas où les octets ne sont pas entièrement écrits avant le rinçage.

Jetez un oeil un ceci: écriture MemoryStream à l'objet de réponse

J'ai eu le même problème et la seule solution qui a fonctionné pour moi était:

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

J'ai eu le même problème alors que je tente d'ouvrir .docx et .xlsx documents. Je résous le problème en définissant le cacheability à ServerAndPrivate au lieu de NoCache

il est ma méthode pour appeler document:

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();          
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top