2016-02-19 2 views
0

У меня есть файл размером 4 ГБ, в котором мне нужно выполнить некоторые операции. У меня есть сценарий Bash, чтобы сделать это, но Bash кажется плохо подходит для чтения больших файлов данных в массив. Поэтому я решил разбить файл с awk.Эффективное разделение больших файлов (в настоящее время используется awk)

Мой текущий сценарий:

for((i=0; i<100; i++)); do awk -v i=$i 'BEGIN{binsize=60000}{if(binsize*i < NR && NR <= binsize*(i+1)){print}}END{}' my_large_file.txt &> my_large_file_split$i.fastq; done 

Однако проблема с этим сценарием является то, что он будет читать и цикл через этот большой файл в 100 раз (что предположительно приведет к примерно 400GB ИО).

ВОПРОС: Есть ли лучшая стратегия чтения в большом файле один раз? Возможно, запись в файлы в awk вместо перенаправления его вывода?

+1

Почему бы просто не использовать 'split (1)'? – peak

+0

Это похоже на разумное решение. –

ответ

1

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

awk -v binsize=60000 ' 
    BEGIN { 
    outfile="output_chunk_1.txt" 
    } 
    count > binsize { 
    if (filenum>1) { 
     close(outfile) 
    } 
    filenum++ 
    outfile="output_chunk_" filenum ".txt" 
    count=0 
    } 
    { 
    count++ 
    print > outfile 
    } 
' my_large_file.txt 

Я не тестировал этот код, так что если он не работает дословно, по крайней мере, это должно дать вам представление о стратегии использования. :-)

Идея состоит в том, что мы перейдем к файлу, обновив имя файла в переменной всякий раз, когда количество строк для фрагмента превышает binsize. Обратите внимание, что close(outfile) не является строго необходимым, так как awk, конечно, закрывает любые открытые файлы, когда он выйдет, но он может сэкономить вам несколько байтов памяти на каждый дескриптор файла (что будет иметь значение только в том случае, если у вас много файлов вывода).


Это сказал, вы могли бы сделать почти то же самое в Баш в одиночку:

#!/usr/bin/env bash 

binsize=60000 

filenum=1; count=0 

while read -r line; do 

    if [ $count -gt $binsize ]; then 
    ((filenum++)) 
    count=0 
    fi 

    ((count++)) 

    outfile="output_chunk_${filenum}.txt" 
    printf '%s\n' "$line" >> $outfile 

done < my_large_file.txt 

(также тестировалась.)

И хотя я бы ожидать AWK решение для быть быстрее, чем bash, может не помешать делать ваши собственные тесты. :)

+0

У меня не было возможности протестировать ваш конкретный скрипт, но ключом к выводу awk для разделения файлов является 'outfile =" output_chunk_ "filenum" .txt "' и 'print> outfile' (который я использовал для решения этой проблемы). По сравнению с моим оригинальным сценарием (который я проецировал на 800 минут) этот метод занимает около 30 минут. Благодаря! –