2015-07-09 2 views
1

У меня есть CSV, который выглядит как этотОбъединение CSV линий в огромном файле

783582893T,2014-01-01 00:00,0,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582893T,2014-01-01 00:15,1,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582893T,2014-01-01 00:30,2,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582855T,2014-01-01 00:00,0,128,35.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582855T,2014-01-01 00:15,1,128,35.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582855T,2014-01-01 00:30,2,128,35.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
... 
783582893T,2014-01-02 00:00,0,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582893T,2014-01-02 00:15,1,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582893T,2014-01-02 00:30,2,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 

хотя есть 5 миллиардов записей. Если вы заметили первый столбец и часть 2-го столбца (день), три из этих записей объединяются вместе и всего лишь разбивка на 15-минутные интервалы в течение первых 30 минут этого дня.

Я хочу, чтобы выход выглядеть

783582893T,2014-01-01 00:00,0,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
783582855T,2014-01-01 00:00,0,128,35.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 
... 
783582893T,2014-01-02 00:00,0,124,29.1,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y,40.0,0.0,40,40,5,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,Y 

Где первые 4 столбцов повторяющихся строк пропущены, а остальные столбцы в сочетании с первой записью в своем роде. В основном я конвертирую день с каждой строки в 15 минут, каждая строка - 1 день.

Поскольку я буду обрабатывать 5 миллиардов записей, я думаю, что лучше всего использовать регулярные выражения (и EmEditor) или какой-то инструмент, который сделан для этого (многопоточность, оптимизирован), а не специально запрограммированное решение. Хотя я открыт для идей в nodeJS или C#, которые являются относительно простыми и супер быстрыми.

Как это можно сделать?

+1

Есть ли всегда 3 записи для каждого? – DLeh

+0

Итак, группируйте строки по первому столбцу, возьмите первые 4 столбца из первой строки (они должны быть одинаковыми для всех строк в группе), а затем добавьте остальные столбцы из других строк в первую. Это верно? –

+0

Да, всегда есть 3 записи (технически есть 96 записей, но решение, которое работает для этих 3, не должно быть трудно адаптировать к 96) – ParoX

ответ

2

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

using (StreamReader sr = new StreamReader("inputFile.txt")) 
using (StreamWriter sw = new StreamWriter("outputFile.txt")) 
{ 
    string line1; 
    int counter = 0; 
    var lineCountToGroup = 3; //change to 96 
    while ((line1 = sr.ReadLine()) != null) 
    { 
     var lines = new List<string>(); 
     lines.Add(line1); 
     for(int i = 0; i < lineCountToGroup - 1; i++) //less 1 because we already added line1 
      lines.Add(sr.ReadLine()); 

     var groupedLine = lines.SomeLinqIfNecessary();//whatever your grouping logic is 
     sw.WriteLine(groupedLine); 
    } 
} 

Disclaimer- непроверенный код, без обработки ошибок и при условии, что на самом деле есть правильное количество линий повторяется, и т.д. Вы бы, очевидно, нужно сделать некоторые хитрости для вашего точного сценария.

+1

Я сомневаюсь, что это хорошее решение для 5-ти миллиардов записей. Почему бы не читать/писать последовательно? –

+0

Размер файла 500 ГБ, я думаю, что это все прочитало бы в памяти. – ParoX

+0

Не должно быть трудно адаптироваться к чему-то, что могло бы работать при загрузке и сохранении строк за строкой, а не сразу. –

1

Вы могли бы сделать что-то вроде этого (непроверенного кода без обработки ошибок - но должно дать вам общую суть этого):

using (var sin = new SteamReader("yourfile.csv") 
using (var sout = new SteamWriter("outfile.csv") 
{ 
    var line = sin.ReadLine(); // note: should add error handling for empty files 
    var cells = line.Split(","); // note: you should probably check the length too! 
    var key = cells[0];   // use this to match other rows 
    StringBuilder output = new StringBuilder(line); // this is the output line we build 
    while ((line = sin.ReadLine()) != null) // if we have more lines 
    { 
     cells = line.Split(","); // split so we can get the first column 
     while(cells[0] == key)  // if the first column matches the current key 
     { 
      output.Append(String.Join(",",cells.Skip(4))); // add this row to our output line 
     } 
     // once the key changes 
     sout.WriteLine(output.ToString());  // write out the line we've built up 
     output.Clear(); 
     output.Append(line);   // update the new line to build 
     key = cells[0];    // and update the key 
    } 
    // once all lines have been processed 
    sout.WriteLine(output.ToString()); // We'll have just the last line to write out 
} 

Идея заключается в петле через каждую строку в свою очередь, и следить за текущее значение первого столбца. Когда это значение изменится, вы выпишите строку output, которую вы создали, и обновите key. Таким образом, вам не нужно беспокоиться о том, сколько совпадений у вас есть, или если вам не хватает нескольких очков.

Обратите внимание, что более эффективно использовать StringBuilder для output, а не String, если вы собираетесь объединить 96 строк.

0

Определите ProcessOutputLine для хранения объединенных строк. Вызовите ProcessLine после каждой ReadLine и в конце файла.

string curKey  ="" ; 
string keyLength = ... ; // set totalength of 4 first columns 
string outputLine = "" ; 

private void ProcessInputLine(string line) 
{ 
    string newKey=line.substring(0,keyLength) ; 
    if (newKey==curKey) outputline+=line.substring(keyLength) ; 
    else 
    { 
    if (outputline!="") ProcessOutPutLine(outputLine) 
    curkey = newKey ; 
    outputLine=Line ; 
} 

EDIT: это решение очень похоже на Matt Берланда, единственное заметное отличие в том, что я не использую Разделить функции.

+0

На самом деле очень важным отличием является то, что вы полагаетесь на фиксированную ширину для столбцов, что хорошо, если они на самом деле фиксированы, но не так много, если они не являются. Теперь, вероятно, (хотя OP необходимо будет подтвердить), чтобы угадать, что * как минимум * первый столбец фиксированной длины. –

Смежные вопросы