2017-01-20 69 views
0

我有一個代碼,它從大小約爲80MB的10個文件中讀取文本。然而,我無法做到這一點成功(取決於我嘗試的方式),它在第3至第7次迭代中失敗。評論過的線是我嘗試閱讀它的方式,每個都失敗了。從多個文件讀取會導致OutOfMemory異常

var lines = new List<string>(); 
var text = string.Empty; 
for (int i = 0; i < 10; i++) 
{ 
    try 
    { 
     //lines.AddRange(File.ReadAllLines(dirPath + string.Format(@"commands{0}.txt", i))); 
     //lines.Add(File.ReadAllText(dirPath + string.Format(@"commands{0}.txt", i))); 
     //lines.Add(text); 

     var bytes = File.ReadAllBytes(dirPath + string.Format(@"commands{0}.txt", i)); 
     text += Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes); 
    } 
    catch (Exception e) 
    { 
     //OutOfMemory exception 
    } 
} 

我在做什麼錯?什麼被封頂? MB允許應用程序,字符串的長度,列表中項目的數量?等等。?

+0

之後你對這個「文本」做什麼?如果您稍後要寫它,或者將字節數組一次直接轉換爲字符串,而不是一次一個文件,那麼將其存儲爲字節數組可能更高效。 –

+1

你只是內存不足而已。這個問題太粗糙了,不能提供替代方案,沒有人能說出爲什麼你需要存儲這麼多的文本。但它肯定是一個非常老套的問題。項目「>」屬性「>」生成「選項卡,然後取消選中」首選32位「選項。你不喜歡它。 –

回答

1

textstring對象,它有一個限制。 What is the maximum possible length of a .NET string?

你可以使用StringBuilder,它可以通過附加到它的限制之外來增長。 https://msdn.microsoft.com/en-us/library/system.text.stringbuilder.maxcapacity(v=vs.110).aspx

首先加上using System.Text

StringBuilder sb = new StringBuilder(); 
for (int i = 0; i < 1000; i++) 
{ 
    var bytes = File.ReadAllBytes(dirPath + string.Format(@"commands{0}.txt", i)); 
    sb.Append(Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes)); 
} 
+0

10x80MB = 800 MB,仍然小於2GB –

+0

OP應該使用StringBuilder,但出於不同的原因。 –

+0

你說得對。我只是想知道這些文件的文件組合內容以某種方式超出了某種程度。我在等待OP是否能夠恢復發佈的解決方案。 –

1

問題出在string textstring是不可變的。這意味着當您在創建後更改string時,將會創建新的string對象。

這樣做:

text += Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes); 

你在每次迭代創建對象(甚至比一個對象的更多 - Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes);創建一個對象,然後你做text +=創建一個多個對象)。

假設您已經讀取第一個文件,然後通過第二個文本追加此string - 將存儲包含來自文件的文本的舊string和包含來自內存中兩個文件的文本的新string。舊的string被存儲但不需要。

有很多不需要的內存,但垃圾收集還沒有完成(這就是爲什麼有時你會在第3次迭代中得到異常,有時在第7次 - 如果GC發生,你走得更遠)。

爲了避免這種考慮,使用byte數組或StringBuilder而不是string

關於List<string>

內部列表擁有一個數組,當存在內存分配不連續的(連續)區這個數組,你會得到OutOfMemoryException了。

您可以嘗試使用LinkedList<string>來代替。

使用StringBuilder

StringBuilder sb = new StringBuilder(); 
for (int i = 0; i < 10; i++) 
{ 
    try 
    { 
     var bytes = File.ReadAllBytes(dirPath + string.Format(@"commands{0}.txt", i)); 

     sb.Append(Environment.NewLine); 
     sb.Append(System.Text.Encoding.UTF8.GetString(bytes));  

     //avoid sb.Append(Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes)) 
     //because you still create unnecessary object doing concatenation (+)  
    } 
    catch (Exception e) 
    { 
     //OutOfMemory exception 
    } 
} 

//you can cast "sb" to "string" 
string res = sb.ToString(); 

但是,你應該考慮創建一個新的解決方案。在內存中保存800MB並不是最好的。

相關問題