2010-07-29 14 views
9

Używam FILESTREAM dla odczytać dużego pliku (> 500 MB) i otrzymuję OutOfMemoryException.OutOfMemoryException kiedy wysłać duży plik 500MB za pomocą FileStream ASPNET

używam ASP.NET, .NET 3.5, Win2003, IIS 6.0

chcę tego w moim app:

odczytu danych z Oracle

Rozpakuj plik przy użyciu FileStream i BZip2

Odczytaj plik nieskompresowany i wyślij go na stronę asp.net do pobrania.

Kiedy czytam plik z dysku, nie zawodzi !!! i dostać OutOfMemory ...

. Mój kod to:

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

Teraz dokładniej określam mój problem.

plik Zdekompresuj użyciu FileStream i BZip2 jest OK, wszystko jest w porządku.

Problem jest następujący:

Czytaj tłuszczu duży plik na dysku (> 500 MB), w byte [] i wysłać bajtów na odpowiedź (ASP.NET) do pobrania go.

Kiedy użycie

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

public static byte[] ReadFully 

pojawia się błąd: OutOfMemoryException ...

Jeśli lepiej BufferedStream niż Stream (FileStream, MemoryStream, ...) ??

Korzystanie BufferedStream, mogę czytać duży plik 700 MB ?? (Dowolny kod źródłowy próbki za pomocą BufferedStream do pobierania dużego pliku)

myślę, że jest to pytanie nie „jak odczytać plik 500MB do pamięci?” , Ale "jak wysłać duży plik do strumienia ASPNET Response?"

znalazłem ten kod przez 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); 
    } 
} 

Czy to dobry kod ?? jakiekolwiek ulepszenia dla wysokiej wydajności?

kolega powiedzieć mi, użyj

Response.TransmitFile(filePath); 

Teraz kolejne pytanie, lepsze TransmitFile lub kodu przez Cheeso ??

Wiele lat temu, w MSDN Magazine pojawia się wielki artykuł na ten temat, ale nie mogę uzyskać dostępu http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/,

Aktualizacja: Możesz uzyskać dostęp za pomocą webarchive w linku: https://web.archive.org/web/20070627063111/http://msdn.microsoft.com/msdnmag/issues/06/09/WebDownloads/

Wszelkie sugestie, komentarze , źródło przykładowego kodu?

Odpowiedz

16

Stworzyłem stronę pobierania, która pozwala użytkownikowi pobrać do 4 GB (może być więcej) kilka miesięcy temu. Oto mój opis roboczy:

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

Nie musisz przechowywać całego pliku w pamięci, po prostu go przeczytaj i napisz do strumienia odpowiedzi w pętli.