чтение нескольких файлов CSV

нужно вытащить тонну информации, т. е.

file1:

10948|Book|Type1 

file2:

 SHA512||0||10948 

file3:

 0|10948|SHA512|c3884fbd7fc122b5273262b7a0398e63 

Я бы хотел, чтобы это было так

  c3884fbd7fc122b5273262b7a0398e63|SHA512|Type1|Book 

У меня нет доступа к реальной базе данных, есть ли способ сделать это? В основном ищет $id = $file1[0]; if($file3[1] == $id) $id = $file1[0]; if($file3[1] == $id) или что-то еще более эффективно.

Каждый файл CSV находится в любом месте от линий 100k-300k. Мне все равно, если это займет некоторое время, я могу просто позволить ей работать на EC2 некоторое время.

Solutions Collecting From Web of "чтение нескольких файлов CSV"

 $data = array(); $fh = fopen('file1') or die("Unable to open file1"); while(list($id, $val1, $val2) = fgetcsv($fh, 0, '|')) { $data[$id]['val1'] = $val1; $data[$id]['val2'] = $val2; } fclose($fh); $fh = fopen('file2') or die ("Unable to open file2"); while(list($method, null, null, null, $id) = fgetcsv($fh, 0, '|')) { $data[$id]['method'] = $method; } fclose($fh); $fh = fopen('file3') or die("Unable to open file3"); while(list(null, $id, null, $hash) = fgetcsv($fh, 0, '|')) { $data[$id]['hash'] = $hash; } fclose($fh); 

Нужно, но вы должны получить массив с данными, которые вы хотите. Вывод его в качестве другого csv оставлен как упражнение для читателя (подсказка: см. fputcsv() ).

Все три файла имеют общее поле (т. Е. В вашем примере «10948» было общим для всех трех строк). Если вас не беспокоит использование большого количества памяти, вы можете загрузить все три файла в другом массиве, установив общее поле в качестве ключа массива и используя цикл foreach, чтобы собрать все три.

Например:

 $result = array(); // File 1 $fh = fopen('file1'); while ( ($data = fgetcsv($fh, 0, '|')) !== FALSE ) $result[$data[0]] = $data; fclose($fh); // File 2 $fh = fopen('file2') while ( ($data = fgetcsv($fh, 0, '|')) !== FALSE ) $result[$data[5]] = array_merge($result[$data[3]], $data); fclose($fh); // File 3 $fh = fopen('file3') while ( ($data = fgetcsv($fh, 0, '|')) !== FALSE ) $result[$data[1]] = array_merge($result[$data[1]], $data); fclose($fh); 

Я бы предложил выполнить слияние-сортировку с использованием основных инструментов unix:
a) сортировать файлы .CSV по столбцам, общим для каждого файла, sort -d "" -K? -К? -К?
b) Использование команды unix 'join' для вывода записей, общих между парами файлов .CSV. Команда «join» работает только с двумя файлами за раз, поэтому вам придется «цепочки» результатов для нескольких источников данных:

  # where 'x' is field number from file A, and 'y' is field number from file B sort -kx "fileA" sort -ky "fileB" join -1x -2y "fileA" "fileB" > file1 sort -kx "fileC" join -1x -2y "file1" "fileC" > file2 sort -kx "fileD" join -1x -2y "file2" "fileD" > file3 etc... 

Это очень быстро и позволяет фильтровать ваши файлы .CSV, как если бы произошло импровизированное соединение базы данных.

Если вам нужно написать свой собственный метод merge-sort в php: (Read Here: Merge Sort )

Простейшая реализация для объединения файлов .CSV является двухэтапной: a) unix сортирует ваши файлы, затем B) «объединяет» все источники параллельно, читая в записи от каждого, ища случай, когда ваше значение в ваши общие поля соответствуют всем другим источникам (JOIN в терминологии базы данных):
правило 1) Пропустить запись, которая меньше (<) ВСЕХ других источников.
правило 2) Когда общее значение записи равно (==), все другие источники имеют совпадение.
правило 3) Когда общее значение записи равно (==), является НЕКОТОРЫМ из другого источника, вы можете использовать логику «LEFT-JOIN», если хотите, иначе пропустите эту запись из всех источников.

Псевдокод для объединения нескольких файлов

 read 1st record from every data source; while "record exists from all data sources"; do for A in each Data-Source ; do set cntMissMatch=0 for B in each Data-Source; do if A.field < B.field then cntMissMatch+=1 end if end for if cntMissMatch == count(Data-Sources) then # found record with lowest values, skip it read next record in current Data-source; break; # start over again looking for lowest else if cntMissMatch == 0 then we have a match, process this record; read in next record from ALL data-sources ; break; # start over again looking for lowest else # we have a partial match, you can choose to have # 'LEFT-JOIN' logic at this point if you choose, # where records are spit out even if they do NOT # match to ALL data-sources. end if end if end for done 

Надеюсь, это поможет.