大容量ファイルの中間部分を読む

大容量ファイルの中間部分を読む

1TBファイルがあります。バイト 12345678901 からバイト 19876543212 まで読み込み、100 MB RAM のコンピュータの stdout に保存したいと思います。

これを行うには、Perlスクリプトを簡単に作成できます。 sysread は 700 MB/s を提供しますが (良好)、syswrite は 30MB/s だけを提供します。私はもっ​​と効率的なものが欲しいです。可能であれば、すべてのUnixシステムにインストールされ、1GB / sを提供できることを望みます。

私の最初の考えは次のとおりです。

dd if=1tb skip=12345678901 bs=1 count=$((19876543212-12345678901))

しかし、これはそれほど効率的ではありません。

編集する:

syswriteエラーをどのように測定したのかわかりません。これは3.5GB / sを提供します。

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悪夢を避けてください。

ベストアンサー1

ブロックサイズが小さいため、遅くなります。最新のGNU ddCoretils v8.16+)、最も簡単な方法は、skip_bytesオプションcount_bytesを使用することです。

in_file=1tb

start=12345678901
end=19876543212
block_size=4096

copy_size=$(( $end - $start ))

dd if="$in_file" iflag=skip_bytes,count_bytes,fullblock bs="$block_size" \
  skip="$start" count="$copy_size"

修正する

fullblock上記で追加したオプション@ギルズの答え。最初はこれが暗示的なものかもしれないと思ったが、count_bytesそうではなかった。

言及された問題は以下の潜在的な問題です。dd何らかの理由で読み取り/書き込み呼び出しが中断されると、データは失われます。ほとんどの場合、そうではない可能性があります(パイプではなくファイルから読み取られるため、確率が低下します)。


andオプションddなしでaを使用することはより困難です。skip_bytescount_bytes

in_file=1tb

start=12345678901
end=19876543212
block_size=4096

copy_full_size=$(( $end - $start ))
copy1_size=$(( $block_size - ($start % $block_size) ))
copy2_start=$(( $start + $copy1_size ))
copy2_skip=$(( $copy2_start / $block_size ))
copy2_blocks=$(( ($end - $copy2_start) / $block_size ))
copy3_start=$(( ($copy2_skip + $copy2_blocks) * $block_size ))
copy3_size=$(( $end - $copy3_start ))

{
  dd if="$in_file" bs=1 skip="$start" count="$copy1_size"
  dd if="$in_file" bs="$block_size" skip="$copy2_skip" count="$copy2_blocks"
  dd if="$in_file" bs=1 skip="$copy3_start" count="$copy3_size"
}

さまざまなブロックサイズを試してみることもできますが、その効果は劇的ではありません。バラより -ddのbsパラメータに最適な値を決定する方法はありますか?

おすすめ記事