2010-01-22 14 views
5

En un sitio ASP.net en mi lugar de trabajo, el siguiente fragmento de código es responsable de manejar las descargas de archivos (NOTA: Response.TransmitFile no se usa aquí porque los contenidos de la descarga son se transmiten desde un archivo ZIP):Uso de la memoria ASP.net durante la descarga

private void DownloadFile(Stream stream) 
{ 
     int bytesRead; 
     int chunkSize = 1048576; //1MB 

     byte[] readBuffer = new byte[chunkSize]; 
     while ((bytesRead = stream.Read(readBuffer, 0, readBuffer.Length)) != 0) 
      { 
       if(!Response.IsClientConnected) 
        break; 
       byte[] chunk = new byte[bytesRead]; 
       Array.Copy(readBuffer,0,chunk,0,bytesRead); 
       Response.BinaryWrite(chunk); 
       Response.Flush(); 
     } 
     stream.Close(); 
} 

Nuestros usuarios frecuencia descarga-cien múltiples archivos MB, lo que puede masticar la memoria del servidor bastante rápido. Mi suposición es que esto se debe al buffering de respuesta. ¿Tiene sentido?

Acabo de leer sobre la propiedad 'buffer' del objeto Response. Si establezco eso en falso, ¿evitará que las llamadas a Response.BinaryWrite() guarden en memoria intermedia los datos en la memoria? En general, ¿cuál es una buena manera de limitar el uso de memoria en esta situación? Tal vez debería transmitir desde el archivo zip a un archivo temporal, luego llamar a Response.TransmitFile()?

EDITAR: Además de las posibles soluciones, estoy muy interesado en las explicaciones del problema de uso de memoria presente en el código anterior. ¿Por qué esto consumiría mucho más de 1MB, a pesar de que Response.Flush es invocado en cada iteración de bucle? ¿Es solo la asignación de montón innecesaria que ocurre en cada iteración de bucle (y no recibe GC'd de inmediato), o hay algo más en funcionamiento?

Respuesta

4

Aquí hay un código en el que estoy trabajando para esto. Utiliza un búfer de 8000 bytes para enviar el archivo en fragmentos. Algunas pruebas informales en un archivo grande mostraron una disminución significativa en la memoria asignada.

int BufferSize = 8000; 
FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read); 
try { 
    long fileSize = stream.Length; 

    long dataLeftToRead = fileSize; 
    int chunkLength; 
    buffer = new Byte[BufferSize]; 

    while (dataLeftToRead > 0) { 
    if (!Response.IsClientConnected) { 
     break; 
    } 
    chunkLength = stream.Read(buffer, 0, BufferSize); 

    Response.OutputStream.Write(buffer, 0, chunkLength); 
    Response.Flush(); 

    dataLeftToRead -= chunkLength; 
    } 
} 
finally { 
    if (stream != null) { 
    stream.Close(); 
} 

editado para corregir un error de sintaxis y un valor perdido

+0

pedante comentario: 8k = 8192 bytes; –

+0

thanx - fixed - we geeks debe ser escrupulosamente exacto – Ray

+2

¿Cuál es la diferencia entre usar Response.Write o escribir directamente en el objeto Response.OutputStream? – Odrade

Cuestiones relacionadas