2010-07-29 9 views
9

Estoy usando Filestream para leer archivos grandes (> 500 MB) y obtengo OutOfMemoryException.OutOfMemoryException cuando envíe un archivo grande de 500MB usando FileStream ASPNET

utilizo Asp.net, .net 3.5, Win2003, IIS 6.0

quiero esto en mi aplicación:

leer datos de Oracle

archivo Descomprimir el uso de FileStream y BZip2

Lea el archivo sin comprimir y envíelo a la página asp.net para descargarlo.

Cuando leo el archivo del disco, ¡falla! y obtener OutOfMemory ...

. Mi código es:

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

Ahora, especifico mi problema mejor.

Descomprimir el archivo con FileStream y BZip2 está bien, todo está bien.

El problema es el siguiente:

leer el archivo grande y gordo en el disco (> 500 MB) en el byte [] y enviar bytes de respuesta (asp.net) para descargarlo.

Cuando uso

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

public static byte[] ReadFully 

me sale el error: OutOfMemoryException ...

Si BufferedStream mejor de lo corriente (FileStream, MemoryStream, ...) ??

Usando BufferedStream, ¿Puedo leer un archivo grande de 700 MB? (cualquier fuente de código de muestra usando BufferedStream para descargar un archivo grande)

Creo que esta es la pregunta: ¿No "cómo leer un archivo de 500mb en la memoria?" , Pero "¿cómo enviar un archivo grande a la corriente de respuesta de ASPNET?"

me encontré con este código por 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); 
    } 
} 

¿Es bueno código ?? ¿Alguna mejora para un alto rendimiento?

Un colega me dicen, el uso

Response.TransmitFile(filePath); 

Ahora, otra pregunta, mejor TransmitFile o código por Cheeso ?? Hace

muchos años, en MSDN Magazine aparece un gran artículo sobre el tema, pero no puedo acceder http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/,

actualización: Puede acceder usando webarchive en el enlace: https://web.archive.org/web/20070627063111/http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/

cualquier sugerencia, comentario , fuente de código de muestra?

Respuesta

16

He creado una página de descarga que permite al usuario descargar hasta 4 gb (puede ser más) hace unos meses. Aquí está mi fragmento de trabajo:

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

No necesita mantener todo el archivo en la memoria, solo léalo y escriba en el flujo de respuesta en un bucle.

Cuestiones relacionadas