2010-07-29 18 views
9

J'utilise Filestream pour lire un gros fichier (> 500 Mo) et j'obtiens le OutOfMemoryException.OutOfMemoryException lors de l'envoi de gros fichier 500 Mo en utilisant FileStream ASPNET

J'utilise Asp.net, .net 3.5, Win2003, IIS 6.0

Je veux dans mon application:

Lire les données de Oracle

fichier Décomprimez en utilisant FileStream et BZip2

Lire le fichier non compressé et l'envoyer à la page asp.net pour le téléchargement.

Lorsque je lis le fichier à partir du disque, échoue !!! et obtenir OutOfMemory ...

. Mon code est:

using (var fs3 = new FileStream(filePath2, FileMode.Open, FileAccess.Read)) 
     { 
      byte[] b2 = ReadFully(fs3, 1024); 
     } 

// http://www.yoda.arachsys.com/csharp/readbinary.html 
public static byte[] ReadFully(Stream stream, int initialLength) 
    { 
    // If we've been passed an unhelpful initial length, just 
    // use 32K. 
    if (initialLength < 1) 
    { 
     initialLength = 32768; 
    } 

    byte[] buffer = new byte[initialLength]; 
    int read = 0; 

    int chunk; 
    while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0) 
    { 
     read += chunk; 

     // If we've reached the end of our buffer, check to see if there's 
     // any more information 
     if (read == buffer.Length) 
     { 
     int nextByte = stream.ReadByte(); 

     // End of stream? If so, we're done 
     if (nextByte == -1) 
     { 
      return buffer; 
     } 

     // Nope. Resize the buffer, put in the byte we've just 
     // read, and continue 
     byte[] newBuffer = new byte[buffer.Length * 2]; 
     Array.Copy(buffer, newBuffer, buffer.Length); 
     newBuffer[read] = (byte)nextByte; 
     buffer = newBuffer; 
     read++; 
     } 
    } 
    // Buffer is now too big. Shrink it. 
    byte[] ret = new byte[read]; 
    Array.Copy(buffer, ret, read); 
    return ret; 
    } 

Maintenant, je précise mieux mon problème.

Décompressez le fichier en utilisant FileStream et BZip2 est OK, tout est bon.

Le problème est le suivant:

fichier Lisez grande graisse dans le disque (> 500 Mo) dans l'octet [] et envoyer octets à la réponse (asp.net) pour le télécharger.

Lorsque l'utilisation

http://www.yoda.arachsys.com/csharp/readbinary.html

public static byte[] ReadFully 

Je reçois l'erreur: OutOfMemoryException ...

Si mieux que BufferedStream flux (FileStream, MemoryStream, ...) ?? En utilisant BufferedStream, puis-je lire un gros fichier de 700 Mo? (tout exemple de source de code utilisant BufferedStream pour télécharger un gros fichier)

Je pense, c'est la question: Pas "comment lire un fichier de 500mb en mémoire?" , Mais "comment envoyer un fichier volumineux au flux de réponse ASPNET?"

Je trouve ce code par Cheeso:

using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 
{ 
    Response.BufferOutput= false; // to prevent buffering 
    byte[] buffer = new byte[1024]; 
    int bytesRead = 0; 
    while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     Response.OutputStream.Write(buffer, 0, bytesRead); 
    } 
} 

est-il du bon code ?? des améliorations pour des performances élevées?

Un collegue me dire, utilisez

Response.TransmitFile(filePath); 

Maintenant, une autre question, mieux TransmitFile ou un code par Cheeso ??

Il y a plusieurs années, dans le magazine msdn semble grand article à ce sujet, mais je ne peux pas accéder à http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/,

Mise à jour: Vous pouvez accéder à l'aide webarchive dans le lien: https://web.archive.org/web/20070627063111/http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/

Toutes les suggestions, commentaires , exemple de code source?

Répondre

16

J'ai créé une page de téléchargement qui permet à l'utilisateur de télécharger jusqu'à 4Go (peut-être plus) il y a quelques mois. Voici mon extrait de travail:

private void TransmitFile(string fullPath, string outFileName) 
    { 
     System.IO.Stream iStream = null; 

     // Buffer to read 10K bytes in chunk: 
     byte[] buffer = new Byte[10000]; 

     // Length of the file: 
     int length; 

     // Total bytes to read: 
     long dataToRead; 

     // Identify the file to download including its path. 
     string filepath = fullPath; 

     // Identify the file name. 
     string filename = System.IO.Path.GetFileName(filepath); 

     try 
     { 
      // Open the file. 
      iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, 
         System.IO.FileAccess.Read, System.IO.FileShare.Read); 


      // Total bytes to read: 
      dataToRead = iStream.Length; 

      Response.Clear(); 
      Response.ContentType = "application/octet-stream"; 
      Response.AddHeader("Content-Disposition", "attachment; filename=" + outFileName); 
      Response.AddHeader("Content-Length", iStream.Length.ToString()); 

      // Read the bytes. 
      while (dataToRead > 0) 
      { 
       // Verify that the client is connected. 
       if (Response.IsClientConnected) 
       { 
        // Read the data in buffer. 
        length = iStream.Read(buffer, 0, 10000); 

        // Write the data to the current output stream. 
        Response.OutputStream.Write(buffer, 0, length); 

        // Flush the data to the output. 
        Response.Flush(); 

        buffer = new Byte[10000]; 
        dataToRead = dataToRead - length; 
       } 
       else 
       { 
        //prevent infinite loop if user disconnects 
        dataToRead = -1; 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new ApplicationException(ex.Message); 
     } 
     finally 
     { 
      if (iStream != null) 
      { 
       //Close the file. 
       iStream.Close(); 
      } 
      Response.Close(); 
     } 
    } 
2

Vous n'avez pas besoin de maintenir le fichier entier en mémoire juste le lire et écrire dans le flux de réponse dans une boucle.