2016-04-06 2 views
0

У меня есть код, который читает текстовый файл и заполняет. Net datatable. Код отлично работает, когда он читает меньший размер текстового файла, который имеет 100 000 строк данных. (см. ниже ниже). Когда я пытаюсь прочитать размер большего текстового файла, например 200 МБ, и имеет 3,6 млн. строк данных, это исключает исключение System.OutofMemoryException. Хотелось бы спросить эффективный способ чтения больших данных в определенные куски.System.OutofMemoryException при чтении большого текстового файла с использованием C#

 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, например. 'new BufferedStream (fileStream, 1024)'. – ManoDestra

+0

Возможный дубликат [Как прочитать большой (1 ГБ) txt-файл в .NET?] (Http://stackoverflow.com/questions/4273699/how-to-read-a-large-1-gb-txt- file-in-net) – bluetoothfx

ответ

0

Если вы измените размер буфера по умолчанию для вашего BufferedStream, тогда он должен будет загружать более крупные файлы для вас с большей эффективностью. Например.

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

Вы можете быть в состоянии уйти с просто используя FileStream, указав размер буфера также, а не BufferedStream. См. this MSDN blog regarding it для получения дополнительной информации.

0

Я могу видеть, что утечка памяти не потому, что чтение всего файла, как вы уже читали построчно var line = reader.ReadLine();. Я думаю, что утечка связана с тем, что размер datatable Table, поскольку он содержит все данные всего файла.
Я предлагаю один из следующих вариантов:
1. Если вы выполняете функции агрегации в строках данных, просто выполните их (например, установите целочисленный счетчик или double max_columnX), не сохраняя целые строки.
2. Если вам действительно нужно сохранить все строки. Создайте базу данных (MSSQL/MYSQL/или любой) и прочитайте файл за строкой - как и вы - и вставьте эти данные в базу данных. Затем запросите базу данных по вашим критериям.
3. Вы можете массово вставить весь файл в базу данных без необходимости его обработки через ваше приложение C#. Вот SQL SERVER example:

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

Edit: Вы можете прикрепить профилировщика памяти, чтобы найти то, что именно занимает большой объем памяти и добавить его к этому вопросу. Это поможет получить лучшие ответы.

+1

можно в .net читать файл кусками и связывать его с datatable? вместо этого читая всю строку записи по строке – 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(); 
Смежные вопросы