2016-04-06 9 views
0

テキストファイルを読み込んで.Netデータテーブルにデータを読み込むコードがあります。コードは、100,000行のデータを持つ小さなサイズのテキストファイルを読み込むと正常に動作します。 (下記のスニペットを参照してください)200MBのような大きなテキストファイルを読み込もうとすると、3.6百万行のデータがSystem.OutofMemoryExceptionをスローします。大きなデータを特定のチャンクに効率的に読み込む方法を尋ねたいと思います。C#を使用して大きなテキストファイルを読み取っているときにSystem.OutofMemoryExceptionが発生しました

 using (var stream = File.Open(filePath, FileMode.Open)) 
     { 
      var content = new StreamContent(stream); 
      var fileStream = content.ReadAsStreamAsync().Result; 

      if (fileStream == null) throw new ArgumentException(Constants.FileEmptyErrorMessage); 

      using (var bs = new BufferedStream(fileStream)) 
      { 
       using (var reader = new StreamReader(bs, Encoding.GetEncoding(Constants.IsoEncoding))) 
       { 


        while (!reader.EndOfStream) 
        { 
         var line = reader.ReadLine(); 
         if (!String.IsNullOrEmpty(line)) 
         { 
          string[] rows = line.Trim().Split(new char[] { ';' }, StringSplitOptions.None); 

          DataRow dr = Table.NewRow(); 
          dr[Constants.Percepcion] = rows[0]; 
          dr[Constants.StartDate] = DateTime.ParseExact(rows[2].ToString(), "ddMMyyyy", 
           CultureInfo.InvariantCulture); 
          dr[Constants.EndDate] = DateTime.ParseExact(rows[3].ToString(), "ddMMyyyy", 
           CultureInfo.InvariantCulture); 
          dr[Constants.CID] = rows[4]; 
          dr[Constants.Rate] = rows[8]; 

          Table.Rows.Add(dr); 
         } 
        } 
       } 
      } 
     } 
+0

行を追加した後で 'テーブル'を使って何をしますか? –

+0

BufferedStreamに別のコンストラクタを使用してバッファサイズを修正できます。 '新しいBufferedStream(ファイルストリーム、1024)'。 – ManoDestra

+0

[.NETで大きな(1 GB)txtファイルを読み取る方法?](http://stackoverflow.com/questions/4273699/how-to-read-a-large-1-gb-txt-ファイル内で) – bluetoothfx

答えて

0

BufferedStreamのデフォルトのバッファサイズを変更すると、大きなファイルが効率的に読み込まれます。例えば。

using (var bs = new BufferedStream(fileStream, 1024)) 
{ 
    // Code here. 
} 

あなたは、単に、FileStreamをを使用してというよりもBufferedStream、また、バッファサイズを指定すると逃げることができるかもしれません。詳細はthis MSDN blog regarding itを参照してください。

0

私は、ファイル全体を読み込むので、あなたはすでにラインvar line = reader.ReadLine();によって行を読んでメモリリークがないことがわかります。私は、ファイル全体のすべてのデータが含まれているので、データテーブルTableのサイズがリークだと思います。
私はこれらのオプションの1つを提案します:
1.データテーブルの行に集約関数を実行する場合は、行全体を保持せずに(整数カウンタを設定するか、max_columnXを2倍するなど)行うだけです。
2.本当にすべての行を保持する必要がある場合。データベース(MSSQL/MYSQL /または任意のもの)を作成し、行ごとにファイルを読み込みます。これらのデータをデータベースに挿入します。次に、条件を指定してデータベースを照会します。
3. C#アプリケーションで処理することなく、ファイル全体をデータベースに一括して挿入できます。ここではSQL Serverのexample次のとおりです。

BULK INSERT AdventureWorks2012.Sales.SalesOrderDetail 
    FROM 'f:\orders\lineitem.tbl' 
    WITH 
    (
     FIELDTERMINATOR =';', 
     ROWTERMINATOR = '\n', 
     FIRE_TRIGGERS 
    ); 

編集: あなたは正確に大容量メモリを必要なものを見つけるために、メモリプロファイラを添付し、質問に追加することができます。より良い回答を得るのに役立ちます。

+1

.netではチャンクでファイルを読み取り、それをデータテーブルにバインドすることは可能ですか?代わりに行ごとにレコードの行全体を読む – PooThePanda

+0

@PooThePanda、良いアイデア。一括挿入のための私の編集された答えを見てください。 –

+0

は、SQLで一括挿入を試みます。 – PooThePanda

0

ここでは、大きなテキストファイルを読みました。バッファード蒸気を使用する必要はありません。

var filteredTextFileData = (from textFileData in File.ReadAllLines(_filePathList[0]).Skip(1).Where(line => !string.IsNullOrEmpty(line)) 
        let textline = textFileData.Split(';') 
        let startDate = DateTime.ParseExact(textline[2].ToString(), Constants.DayMonthYearFormat, CultureInfo.InvariantCulture) 
        let endDate = !string.IsNullOrEmpty(textline[3]) ? DateTime.ParseExact(textline[3], Constants.DayMonthYearFormat, CultureInfo.InvariantCulture) : (DateTime?)null 
        let taxId = textline[0] 
        join accountList in _accounts.AsEnumerable() 
        on taxId equals accountList.Field<string>(Constants.Comments) 
        where endDate == null || endDate.Value.Year > DateTime.Now.Year || (endDate.Value.Year == DateTime.Now.Year && endDate.Value.Month >= DateTime.Now.Month) 
        select new RecordItem() 
        { 
         Type = Constants.Regular, 
         CustomerTaxId = taxId, 
         BillingAccountNumber = accountList.Field<Int64>(Constants.AccountNo).ToString(), 
         BillingAccountName = accountList.Field<string>(Constants.BillCompany), 
         StartDate = DateTime.Compare(startDate, accountList.Field<DateTime>(Constants.DateActive)) < 1 ? accountList.Field<DateTime>(Constants.DateActive) : startDate, 
         EndDate = endDate, 
         OverrideRate = 0, 
         Result = Constants.NotStarted, 
         TaxCode = _taxCode, 
         ImpliedDecimal = 4 
        }).ToList(); 
関連する問題