У меня есть файл 1 ТБ. Я хотел бы прочитать от байта 12345678901 до байта 19876543212 и поставить его на стандартный вывод на машине с 100 МБ ОЗУ.
Я могу легко написать Perl-скрипт, который делает это. sysread обеспечивает 700 МБ / с (что нормально), но syswrite обеспечивает только 30 МБ / с. Я хотел бы что-то более эффективное, желательно что-то, что устанавливается в каждой системе Unix и может доставлять порядка 1 ГБ / с.
Моя первая идея:
dd if=1tb skip=12345678901 bs=1 count=$((19876543212-12345678901))
Но это не эффективно.
Редактировать:
Я понятия не имею, как я измерил syswrite неправильно. Это обеспечивает 3,5 ГБ / с:
perl -e 'sysseek(STDIN,shift,0) || die; $left = shift; \
while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ \
$left -= $read; syswrite(STDOUT,$buf);
}' 12345678901 $((19876543212-12345678901)) < bigfile
и избегает yes | dd bs=1024k count=10 | wc
кошмара.
bs=1M iflag=skip_bytes,count_bytes
Ответы:
Это медленно из-за небольшого размера блока. Используя недавнюю версию GNU
dd
( coreutils v8.16 + ), самый простой способ - использовать параметрыskip_bytes
иcount_bytes
:Обновить
fullblock
опция добавлена выше согласно ответу @Gilles . Сначала я подумал, что это может подразумеватьсяcount_bytes
, но это не так.Упомянутые проблемы являются потенциальной проблемой, приведенной ниже. Если
dd
вызовы чтения / записи прерваны по какой-либо причине, данные будут потеряны. В большинстве случаев это маловероятно (шансы несколько снижаются, поскольку мы читаем из файла, а не из канала).Использование
dd
без параметровskip_bytes
иcount_bytes
более сложно:Вы также можете поэкспериментировать с различными размерами блоков, но выигрыш не будет очень значительным. Смотрите - Есть ли способ определить оптимальное значение параметра bs для dd?
источник
bs
не является факторомskip
?skip
это количество блоков, а не байтов. Может быть , вы запутались , так какskip_bytes
используется в первом примере значениемskip
является в байтах там?bs
есть4,096
, которые означают , что вы не можете более точно показывать , что4,096
байтыdd
с первым и последним использованиемbs=1
, чтобы скопировать данные, которые не начинаются или не заканчиваются при выравнивании блоков.bs=1
говоритdd
читать и писать по одному байту за раз. Для каждого вызоваread
иwrite
обработки накладных расходов , что делает это медленным. Используйте больший размер блока для достойной производительности.При копировании весь файл, по крайней мере под Linux, я обнаружил , что
cp
иcat
быстрее , чемdd
, даже если вы указываете большой размер блока.Чтобы скопировать только часть файла, вы можете перейти
tail
вhead
. Это требует GNU coreutils или какой-либо другой реализации, котораяhead -c
должна копировать указанное количество байтов (tail -c
в POSIX, ноhead -c
нет). Быстрый тест на Linux показывает, что это медленнее, чемdd
, вероятно, из-за конвейера.Проблема в
dd
том, что он ненадежен: он может копировать частичные данные . Насколько я знаю,dd
безопасно читать и записывать в обычный файл - см. Когда dd подходит для копирования данных? (или, когда read () и write () частичны) - но только до тех пор, пока это не прервано сигналом . С GNU coreutils вы можете использоватьfullblock
флаг, но он не переносим.Другая проблема
dd
заключается в том, что может быть трудно найти работающий счетчик блоков, поскольку количество пропущенных байтов и количество переданных байтов должны быть кратными размеру блока. Вы можете использовать несколько вызововdd
: один для копирования первого частичного блока, один для копирования основной части выровненных блоков и один для копирования последнего частичного блока - см . Ответ Грэма для фрагмента оболочки. Но не забывайте, что когда вы запускаете скрипт, если вы не используетеfullblock
флаг, вам нужно молиться,dd
чтобы скопировать все данные.dd
возвращает ненулевое состояние, если копия является частичной, поэтому легко обнаружить ошибку, но нет практического способа ее исправить.POSIX не может предложить ничего лучшего на уровне оболочки. Мой совет - написать небольшую специализированную программу на C (в зависимости от того, что именно вы реализуете, вы можете назвать ее
dd_done_right
илиtail_head
илиmini-busybox
).источник
yes | dd bs=1024k count=10 | wc
проблемы раньше. Насти.С
dd
:Альтернативно с
losetup
:А потом
dd
,cat
... устройство петли.источник
Вот как вы можете сделать это:
Это все, что действительно необходимо - это не требует намного большего. На первом месте
dd count=0 skip=1 bs=$block_size1
будетlseek()
обычный ввод файлов практически мгновенно. Там нет шансов пропущенных данных или любой другой неправды об этом, вы можете просто искать прямо к вашей желаемой стартовой позиции. Поскольку файловый дескриптор принадлежит оболочке иdd
они просто наследуют его, они будут влиять на его положение курсора, поэтому вы можете просто выполнить его пошагово. Это действительно очень просто - и нет стандартного инструмента, лучше подходящего для этой задачи, чемdd
.Это использует размер блока 64 КБ, который часто идеален. Вопреки распространенному мнению, большие размеры блоков не заставляют
dd
работать быстрее. С другой стороны, крошечные буферы тоже не годятся.dd
ему нужно синхронизировать свое время в системных вызовах, чтобы ему не нужно было ждать при копировании данных в память и снова, а также чтобы не нужно было ждать системных вызовов. Таким образом, вы хотите, чтобы это заняло достаточно времени, чтобы следующийread()
не должен был ждать последнего, но не настолько, чтобы вы буферизировали в больших размерах, чем это необходимо.Итак, первый
dd
переходит на стартовую позицию. Это занимает нулевое время. Вы можете вызвать любую другую программу, которая вам нравится в этот момент, чтобы прочитать ее стандартный вывод, и она начнет читать непосредственно с желаемым байтовым смещением. Я звоню другому,dd
чтобы прочитать((interval / blocksize) -1)
количество блоков в стандартный вывод.Последнее, что необходимо, это скопировать модуль (если есть) предыдущей операции деления. И это все.
Кстати, не верьте этому, когда люди заявляют факты на лице без доказательств. Да, это возможно для
dd
краткого чтения (хотя такие вещи невозможны при чтении с исправного блочного устройства - таким образом, имя) . Такое возможно только в том случае, если вы неправильно буферизуетеdd
поток, который читается не с блочного устройства. Например:В обоих случаях
dd
копируются все данные. В первом случае возможно (хотя и маловероятно,cat
что ), что некоторые из выходных блоков, которыеdd
копируются, будут равны байтам «$ num», потому чтоdd
спецификация предназначена только для буферизации чего-либо вообще, когда буфер специально запрашивается по его команде. линия.bs=
представляет собой максимальный размер блока , так как цель изdd
в реальном времени ввода / вывода.Во втором примере я явно указываю выходной размер блока и
dd
буферизует чтение до тех пор, пока не будут выполнены полные записи. Это не влияет на то,count=
что основано на входных блоках, но для этого вам просто нужен другойdd
. Любая дезинформация, предоставленная вам в противном случае, должна игнорироваться.источник