Як працює `wc -l`?


11

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

Я реалізував багато рішень і знайшов одне. Але під час мого пошуку я думав подивитися, як це wc -lпрацює. Я нічого не міг знайти в Google.

Хоча я знайшов рішення своєї проблеми, я все ж хотів би знати, як wc -lпрацює, оскільки він може за кілька секунд обчислити кількість рядків файлу з 92 мільйонами рядків!

Як?


Відповіді:


20

Він читає весь файл і підраховує кількість закінчень рядків. Підрахунок закінчень рядків дійсно дешевий; більшість часу витрачається на читання файлу. Якщо файл (в основному) знаходиться в кеш-пам'яті буфера, це теж буде дешевим. В іншому випадку це буде залежати від швидкості зберігання файлів.

Іншими словами, магії немає.


Він читає весь файл і рахує кількість закінчень рядків? Щоб дійти до кінця рядка, чи не в основному він читає весь рядок до кінця? І це означало б, що вона прочитала весь файл, правда?
detraveller

@detraveller: так, він читає весь файл, як я вже сказав. Він не читає його рядок за рядком або все відразу, але він зчитує кожен символ і підраховує, скільки з цих символів - це рядкові символи.
rici

7

WC просто зчитує файл у блоках необроблених байтів (бажано в кратних розмірах природного розміру блоку базової файлової системи, на якій знаходиться файл).
Потім він просто сканує через буфер, рахуючи символи кінця рядка. (Він також рахує пробіли, вкладки, формати та інші спеціальні символи, на випадок, якщо вам потрібна інша інформація, ніж вихід -l.)

Читання з диска - це дорога частина з точки зору швидкості. Сканування буфера займає недбалий час порівняно з цим.

Скажімо, у вас 90 мільйонів рядків із середнім 100 символами на рядок.
Це близько 9.000.000.000 символів або близько 860 МБ.
Пристойний ПК із накопичувачем SATA-3Gb / s зробить це за 10 секунд. Навіть у відносно повільній файловій системі з одночасною деякою іншою діяльністю.
Швидка машина з певною настройкою продуктивності та оптимізованою файловою системою може робити це за 5 секунд, навіть не вдаючись до SATA-6G та SSD-накопичувача.


він просто сканує через буфер підрахунку \nсимволів кінця рядка ( ) - "-l, - лінії друкує кількість ліній нового рядка \ n \" - витягнутий зwc.c
Рахул Патіль

@RahulPatil Більшість реалізацій набагато більше, ніж просто підрахунок нових рядків. Дивіться приклад, згаданий у верхньому коментарі вище. Це джерело туалету, який використовується в основних утилітах Linux.
Тонні

так .. я це бачив .. просто згадую, тому що питання про wc -l.. вибачте ...
Рахул Патіл

3

Ласкаво просимо у світ вільного програмного забезпечення. Ви завжди можете подивитися вихідний код

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

Що я знаю, це те, що wc не відкриває сам файл, але просить ОС це зробити, це багато в чому залежить від ОС, і, звичайно, від того, як файл зберігається. Окрім цього, я б очікував, що повинні бути правильні методи програмування, наприклад, не намагаючись прочитати файл в цілому відразу і т.д.


Що ви маєте на увазі під "не намагаючись прочитати весь файл відразу"?
detraveller

Я маю на увазі завантаження файлу в пам'ять, скажімо, в один рядок / масив. У співтоваристві Perl це називається каламутністю, і це швидке та брудне рішення, яке добре, коли ви знаєте, що будете читати кілька рядків, але подача справді величезного файлу в пам’ять рідко є гарною ідеєю.
Алоїз Магдал

1
З іншого боку, ви можете прочитати, скажімо, 64 KiB, порахувати нові рядки та викинути їх, повторити ... Таким чином, ви з'їсте щонайбільше понад 64 KiB, як би не був величезний файл. (Це менш просто, коли ти розумієш, що новий рядок може мати 2 байти і, таким чином,
ділитися

Не надто важливо, але: "оскільки wc не відкриває сам файл, але просить ОС це зробити" - не впевнений, що ви маєте на увазі під цим, але я сумніваюся, що це правильно. Це, звичайно, читання всіх персонажів самостійно.
Ар'ян

2
@Arjan Хоча, якщо бути справді правильним: виключаючи вбудовані системи, програми навряд чи справді самі читають, вся суть Kernel та OS полягає в тому, що вона робить для них роботу. Фактично, відкрити (), закрити (), прочитати () (будь то Linux, Windows, socket або файл) - це все системні виклики, які фактичні програми не мають уявлення про внутрішню роботу.
Алоїс Магдал
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.