Il codice che si visualizza, legge tutto il contenuto del file 500mb in un'area contigua in memoria. Non sorprende che si verifichi una condizione di esaurimento della memoria.
La soluzione è "non farlo".
Cosa stai cercando di fare ?
Se si desidera leggere completamente un file, è molto più semplice del metodo ReadFully che si utilizza. Prova questo:
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[fs.Length];
int bytesRead = fs.Read(buffer, 0, buffer.Length);
// buffer now contains the entire contents of the file
}
Ma ... l'utilizzo di questo codice non risolverà il problema. Potrebbe funzionare per un file da 500 MB. Non funzionerà con un file da 750 MB o con un file da 1 GB. Ad un certo punto raggiungerai il limite di memoria sul tuo sistema e avrai lo stesso errore di memoria esaurita con cui hai iniziato.
Il problema è che si sta tentando di tenere in memoria l'intero contenuto del file in una volta. Questo di solito non è necessario ed è destinato a fallire man mano che i file crescono di dimensioni. Non è un problema quando la dimensione del file è 16k. A 500mb, è l'approccio sbagliato.
Questo è il motivo per cui ho chiesto più volte, , cosa stai provando a fare?
Sembra che si desideri inviare il contenuto di un file a un flusso di risposta ASPNET. Questa è la domanda. Non "come leggere un file 500mb in memoria?" Ma "come inviare un file di grandi dimensioni al flusso di risposta ASPNET?"
Per questo, ancora una volta, è abbastanza semplice.
// emit the contents of a file into the ASPNET Response stream
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);
}
}
ciò che fa è iterativo di leggere un pezzo dal file, e scrivere quel pezzo al flusso di risposta, fino a quando non c'è più niente da leggere nel file. Questo è ciò che si intende per "streaming IO". I dati passano attraverso la tua logica, ma non vengono mai tenuti tutti in un unico posto, proprio come un flusso d'acqua passa attraverso una chiusa. In questo esempio, non v'è più di 1k di dati del file in memoria in una sola volta (beh, non detenute dal il codice applicazione, in ogni caso. Ci sono altri buffer di IO inferiori nello stack.)
Questo è un modello comune nell'IO in streaming. Impara, usalo.
L'unico trucco per il pompaggio dei dati in Response.OutputStream di ASPNET è impostare BufferOutput = false
. Per impostazione predefinita, ASPNET tenta di bufferizzare l'output. In questo caso (file 500mb), il buffering è una cattiva idea. L'impostazione della proprietà BufferOutput
su false impedirà a ASPNET di tentare di bufferizzare tutti i dati del file prima di inviare il primo byte. Usalo quando sai che il file che stai inviando è molto grande. I dati verranno comunque inviati correttamente al browser.
E anche questa non è la soluzione completa. Dovrai impostare le intestazioni di risposta e così via. Immagino che tu ne sia consapevole, comunque.
prega, che è il codice migliore, ho utilizzare questo: http://www.yoda.arachsys.com/csharp/readbinary.html Grazie signore –
+1: Sì, destinando la dimensione del buffer che serve è un buona idea ... in realtà, sono sorpreso che .NET non abbia un metodo per leggere un intero file in un array di byte o qualche altra struttura simile. – Powerlord
Lo fa. File.ReadAllBytes http://msdn.microsoft.com/en-us/library/system.io.file.readallbytes.aspx Ma questo non è ciò che questo poster dovrebbe fare. Leggere tutti i byte di un file da 500 MB in memoria è * di solito una cattiva idea *, e in questo caso ... è una pessima idea. Il poster ha chiaramente in mente un obiettivo primario, ma non dichiarato, che non "legge tutti i byte di un file in memoria". Lui * pensa * che ha bisogno di leggere tutti i byte, ma non è vero. – Cheeso