2009-09-10 21 views
8

Tôi đang sử dụng string.split() trong mã C# của tôi để đọc tệp được phân cách bằng tab đọc. Tôi đang phải đối mặt với "ngoại lệ OutOfMemory" như được đề cập dưới đây trong mẫu mã.string.split() "Ngoại lệ bộ nhớ ngoài" khi đọc tệp được phân cách bằng tab

Ở đây tôi muốn biết tại sao sự cố xảy ra với tệp có kích thước 16 MB?

Đây có phải là phương pháp phù hợp hay không?

using (StreamReader reader = new StreamReader(_path)) 
{ 
    //...........Load the first line of the file................ 
    string headerLine = reader.ReadLine(); 

    MeterDataIPValueList objMeterDataList = new MeterDataIPValueList(); 
    string[] seperator = new string[1]; //used to sepreate lines of file 

    seperator[0] = "\r\n"; 
    //.............Load Records of file into string array and remove all empty lines of file................. 
    string[] line = reader.ReadToEnd().Split(seperator, StringSplitOptions.RemoveEmptyEntries); 
    int noOfLines = line.Count(); 
    if (noOfLines == 0) 
    { 
    mFileValidationErrors.Append(ConstMsgStrings.headerOnly + Environment.NewLine); 
    } 
    //...............If file contains records also with header line.............. 
    else 
    { 
    string[] headers = headerLine.Split('\t'); 
    int noOfColumns = headers.Count(); 

    //.........Create table structure............. 
    objValidateRecordsTable.Columns.Add("SerialNo"); 
    objValidateRecordsTable.Columns.Add("SurveyDate"); 
    objValidateRecordsTable.Columns.Add("Interval"); 
    objValidateRecordsTable.Columns.Add("Status"); 
    objValidateRecordsTable.Columns.Add("Consumption"); 

    //........Fill objValidateRecordsTable table by string array contents ............ 

    int recordNumber; // used for log 
    #region ..............Fill objValidateRecordsTable..................... 
    seperator[0] = "\t"; 
    for (int lineNo = 0; lineNo < noOfLines; lineNo++) 
    { 
     recordNumber = lineNo + 1; 
     **string[] recordFields = line[lineNo].Split(seperator, StringSplitOptions.RemoveEmptyEntries);** // Showing me error when we split columns 
     if (recordFields.Count() == noOfColumns) 
     { 
     //Do processing 
     } 
+4

Ngoài ra, Eric Lippert có một blog tuyệt vời về OutOfMemoryExceptions. http://blogs.msdn.com/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx –

+0

Đây có phải là khung công tác nhỏ gọn (ví dụ: Windows Mobile))? – MusiGenesis

Trả lời

12

chia được thực hiện kém, và có vấn đề hiệu suất nghiêm trọng khi áp dụng trên dây lớn. Vui lòng tham khảo this article for details on memory requirements by split function:

Điều gì sẽ xảy ra khi bạn chia tách chuỗi có 1355049 chuỗi phân cách bằng dấu phẩy gồm 16 ký tự, có tổng chiều dài ký tự là 25745930?

  1. một mảng của con trỏ đến đối tượng chuỗi: Tiếp giáp không gian địa chỉ ảo của 4 (con trỏ địa chỉ) * 1355049 = 5420196 (mảng kích thước) + 16 (đối với sổ sách) = 5420212.

  2. phi không gian địa chỉ ảo tiếp giáp cho 1355049 chuỗi, mỗi chuỗi 54 byte. Nó không có nghĩa là tất cả 1,3 triệu chuỗi đó sẽ nằm rải rác trên toàn bộ đống, nhưng chúng sẽ không được phân bổ trên LOH. GC sẽ phân bổ chúng trên các cụm trên Gen0 heap.

  3. Split.Function sẽ tạo mảng nội bộ của System.Int32 [] kích thước 25.745.930, tiêu thụ (102.983.736 bytes) ~ 98MB của LOH, mà là rất tốn kém L.

1

Thử đọc tệp theo chiều dọc thay vì chia toàn bộ nội dung.

10

Hãy thử không đọc toàn bộ tập tin vào một mảng đầu tiên "reader.ReadToEnd()" Đọc dòng tập tin bằng dòng trực tiếp ..

using (StreamReader sr = new StreamReader(this._path)) 
     { 
      string line = ""; 
      while((line= sr.ReadLine()) != null) 
      { 
       string[] cells = line.Split(new string[] { "\t" }, StringSplitOptions.None); 
       if (cells.Length > 0) 
       { 

       } 
      } 
     } 
+0

Nó có tác động khi chúng ta đọc từng dòng –

+1

Nó không hoạt động nếu tất cả dữ liệu của tôi chỉ nằm trong một dòng. – Butzke

4

Tôi muốn giới thiệu đọc từng dòng nếu bạn có thể, nhưng đôi khi chia tách bởi các dòng mới không phải là yêu cầu.

Vì vậy, bạn luôn có thể viết chia tách bộ nhớ hiệu quả của riêng mình. Điều này giải quyết các vấn đề đối với tôi.

private static IEnumerable<string> CustomSplit(string newtext, char splitChar) 
    { 
     var result = new List<string>(); 
     var sb = new StringBuilder(); 
     foreach (var c in newtext) 
     { 
      if (c == splitChar) 
      { 
       if (sb.Length > 0) 
       { 
        result.Add(sb.ToString()); 
        sb.Clear(); 
       } 
       continue; 
      } 
      sb.Append(c); 
     } 
     if (sb.Length > 0) 
     { 
      result.Add(sb.ToString()); 
     } 
     return result; 
    } 
2

Tôi sử dụng của riêng mình. Nó đã được thử nghiệm với 10 bài kiểm tra đơn vị ..

public static class StringExtensions 
{ 

    // the string.Split() method from .NET tend to run out of memory on 80 Mb strings. 
    // this has been reported several places online. 
    // This version is fast and memory efficient and return no empty lines. 
    public static List<string> LowMemSplit(this string s, string seperator) 
    { 
     List<string> list = new List<string>(); 
     int lastPos = 0; 
     int pos = s.IndexOf(seperator); 
     while (pos > -1) 
     { 
      while(pos == lastPos) 
      { 
       lastPos += seperator.Length; 
       pos = s.IndexOf(seperator, lastPos); 
       if (pos == -1) 
        return list; 
      } 

      string tmp = s.Substring(lastPos, pos - lastPos); 
      if(tmp.Trim().Length > 0) 
       list.Add(tmp); 
      lastPos = pos + seperator.Length; 
      pos = s.IndexOf(seperator, lastPos); 
     } 

     if (lastPos < s.Length) 
     { 
      string tmp = s.Substring(lastPos, s.Length - lastPos); 
      if (tmp.Trim().Length > 0) 
       list.Add(tmp); 
     } 

     return list; 
    } 
} 
Các vấn đề liên quan