Використання "голови" або "хвоста" у ВЕЛИЧЕЗНОМ текстовому файлі - 19 ГБ


15

У мене проблема з переглядом фрагментів дуже великого текстового файлу. Цей файл, приблизно 19 Гб, очевидно, занадто великий для перегляду будь-якими традиційними засобами.

Я спробував head 1і tail 1( head -n 1і tail -n 1) обидві команди, з'єднані різними способами (щоб потрапити на шматок посередині), не пощастивши. Моя машина Linux під управлінням Ubuntu 9.10 не може обробити цей файл.

Як обробити цей файл? Моя кінцева мета - налагодити лінії 45000000 та 45000100.


Думаю написати швидкий сценарій Python, щоб прочитати рядки та надрукувати ті, які мені потрібно подати, але я можу уявити, що це потребує багато часу ...
nicorellius

Чи всі лінії однакові?
Пол

@Paul - на жаль, вони не однакової довжини.
nicorellius

Ви можете спробувати splitполегшити роботу з великим файлом.
iglvzx

1
Добре. Будь-яка обробка файлу, що займає великий обсяг, потребує часу, тому відповіді нижче допоможуть у цьому. Якщо ви хочете витягти саме ту частину, яку шукаєте, і приблизно зможете оцінити, де саме ви можете скористатися, ddщоб отримати шматочок, який ви шукаєте. Наприклад dd if=bigfile of=extractfile bs=1M skip=10240 count=5, витягніть 5 Мб з файлу, починаючи з точки 10 ГБ.
Павло

Відповіді:


11

Ви повинні використовувати sed.

sed -n -e 45000000,45000100p -e 45000101q bigfile > savedlines

Це повідомляє sedпро друк рядків 45000000-45000100 включно та вийти з рядка 45000101.


1
Це все ще дуже повільно, майже як head -45000000,45000100p bigfile | хвіст -100> збережені лінії
Дмитро Полушкін

tail+|headшвидше на добрі 10-15%.
Еріх

4

Створіть базу даних MySQL з єдиною таблицею, в якій є одне поле. Потім імпортуйте файл у базу даних. Це дозволить дуже легко шукати певну лінію.

Я не думаю, що щось інше може бути швидшим (якщо headі tailвже не вдасться). Зрештою, додаток, який хоче знайти рядок n, повинен шукати весь файл, поки не знайдеться nнові рядки. Без якогось пошуку (індекс рядка до зміщення байтів у файл) не можна досягти кращої продуктивності.

З огляду на те, як легко створити базу даних MySQL та імпортувати в неї дані, я відчуваю, що це підхід.

Ось як це зробити:

DROP DATABASE IF EXISTS helperDb;
CREATE DATABASE `helperDb`;
CREATE TABLE `helperDb`.`helperTable`( `lineIndex` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `lineContent` MEDIUMTEXT , PRIMARY KEY (`lineIndex`) );
LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable (lineContent);
SELECT lineContent FROM helperTable WHERE ( lineIndex > 45000000 AND lineIndex < 45000100 );

/tmp/my_large_file був би файл, який ви хочете прочитати.

Правильний синтаксис для імпорту файлу зі значеннями, розміщеними на вкладках у кожному рядку, є:

LOAD DATA INFILE '/tmp/my_large_file' INTO TABLE helperDb.helperTable FIELDS TERMINATED BY '\n' (lineContent);

Інша основна перевага цього полягає в тому, що якщо ви вирішите пізніше витягнути інший набір рядків, вам не доведеться знову чекати годин на обробку (якщо, звичайно, не видалити базу даних).


Тож справді це хороше рішення. Я змусив його працювати з sedкомандою нижче, і визначив свої рядки. Але тепер у мене є додаткове запитання, яким може бути краще підходить метод бази даних. Тепер мені потрібно видалити пару сотень рядків з файлу.
nicorellius

Я впевнений, що sedміг би це зробити також. Звичайно, якби у вас були дані в базі даних, було б експортно новий файл експортувати лише з потрібних рядків.
Der Hochstapler

Знову дякую. Я прийняв sedвідповідь (тому що це мені принесло більше задоволення; -), але я дав вам голос, оскільки я буду використовувати ваш метод у майбутньому. Я ціную це.
nicorellius

1
Ви могли б спробувати додати FIELDS TERMINATED BY '\n'до LOAD DATAлінії.
Der Hochstapler

1
Вибачте, у моєму коді сталася помилка. Я також додав правильний синтаксис для вашої справи (перевірено цього разу).
Der Hochstapler

1

Два хороших старі інструменти для великих файлів є joinі split. Ви можете використовувати спліт з --lines=<number>опцією, що дозволяє вирізати файл на кілька файлів певного розміру.

Наприклад split --lines=45000000 huge_file.txt. Отримані частини будуть в xa, xb тощо. Тоді ви можете headчастину xb, яка включала б потрібні вам лінії. Ви також можете "приєднати" файли до одного великого файлу.


Дивовижний, дякую, я зовсім забув про команду розділення.
siliconrockstar

0

У вас є правильні інструменти, але ви використовуєте їх неправильно. Як раніше відповіли в U&L, tail -n +X file | head -n Y(зверніть увагу +), це на 10-15% швидше, ніж sedдля Y-рядків, що починаються з X. І зручно, вам не потрібно явно exitвиконувати процес, як у sed.

хвіст прочитає та відкине перші рядки X-1 (цього не обійти), потім прочитає та надрукує наступні рядки. голова прочитає та надрукує потрібну кількість рядків, а потім вийде. Коли голова виходить, хвіст отримує сигнал SIGPIPE і вмирає, тому з вхідного файлу він не буде прочитати більше, ніж розмір буфера (як правило, кілька кілобайт) рядків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.