web-dev-qa-db-ja.com

末尾の0バイトを除くファイルのサイズを取得する

ダウンロード中のファイルのサイズを知りたいのですが。ファイルは事前に割り当てられているため、du -sdは、最終的なフルサイズを返します。ダウンロードされた量を知りたいので、末尾の0バイトをカウントしたくありません。このサイズの入手方法を教えてください。

aria2cは停止したダウンロードを簡単に再開でき、ダウンロードした長さを そのコントロール(セッション)ファイル に保存していないようです。私は script を書いてtotal_lengthから.aria2制御ファイル。ただし、これは全長であり、ダウンロードされた長さではありません。このスクリプトと 技術仕様 を使用すると、他のプロパティaria2ストアを簡単に取得できます。

コメントからの更新:

Ilkkachuがほのめかしていたので、.aria2ファイルのBITFIELDは実際にはマップのようです。各ビットはファイルチャンクに対応し、1は「ダウンロード済み」を意味します(0は「ダウンロードされていない」ことを意味します)。 BITFIELD LENGTHは、チャンクの数を示します(チャンクサイズは、おそらくファイルのサイズをチャンク数で割ったものです)。ダウンロードの進行状況は、BITFIELDのチャンクの数に対する1の比率によって与えられると確信しています。残念ながら、AFAICTの.aria2ファイルは、少し遅れて、またはダウンロードが中断された直後に更新されるようです。

3
HappyFace

aria2がダウンロードからどれだけ進んでいるかを知る問題だけを考えると、いくつかの選択肢があります。

コメントで説明したように、情報は制御ファイル(filename.aria2)のビットマップにあります。 https://aria2.github.io/manual/en/html/technical-notes.html に記載されています。ビットマップがあることは、最初から直線的に進むHTTPダウンロードにはあまり意味がありませんが、BitTorrentダウンロードなどにはもっと意味があると思います。

次に、重要なフィールドが(od -tx1 file.aria2)とマークされた特定のダウンロード用の制御ファイルの16進ダンプを示します。

0000000 00 01 00 00 00 00 00 00 00 00 00 10 00 00 00 00
                                      ^^^^^^^^^^^ ^^^^^^  
0000020 00 00 82 9d c0 00 00 00 00 00 00 00 00 00 00 00 
        ^^^^^^^^^^^^^^^^^                         ^^^^^^
0000040 01 06 ff ff ff ff ff ff ff ff ff ff ff ff ff ff
        ^^^^^ ^^^... 
0000060 ff ff ff ff ff ff ff ff ff fe 00 00 00 00 00 00


offset 10: 00 10 00 00 => piece length = 0x100000 = 1 MiB
offset 14: 00 00 00 00 
           82 9d c0 00 => file length = 0x829dc000 = 2191376384 (~ 2 GiB)
offset 30: 00 00 01 06 => size of bitmap = 0x0106 = 262 bytes, could fit 2096 pieces
offset 34: ff ff ...   => bitmap

ビットマップのセットビットを数えると、1 MiB(200278016バイト)が少なくとも191個ダウンロードされた後、その特定のダウンロードが中断されました。これは、取得したファイルサイズ201098200バイトとほぼ一致しています。 (実際のファイルはMiBより少し大きいだけで、制御ファイルの飛行中の部分のレコードはそれをマークするかもしれませんが、私は気にしませんでした。私ができるように、事前割り当てはしていませんでしたファイルシステムのサイズとクロスチェックしてください。)

デフォルトでは、aria2cは60秒ごとに制御ファイルを保存しますが、--auto-save-interval=<secs>を使用してそれを変更できます。

--auto-save-interval=<SEC>
       Save a control file(*.aria2) every SEC seconds.  If 0 is
       given, a control file is not saved during download. aria2
       saves  a  control  file  when  it stops regardless of the
       value.  The possible values are between 0 to 600. 
       Default: 60

または、aria2c --log=<logfile>を使用して、ダウンロードの進行状況をログから除外することもできます。進捗状況はDEBUGレベルのメッセージで書き込みキャッシュエントリのみが表示されているように見えますが、有効にすると、ログはかなり詳細になります。

また、--summary-interval=1を使用して、進行状況の出力をstdoutに出力し、ログファイルにリダイレクトすることもできます(ライブ読み取りを非表示にするために--show-console-readout=falseを使用する場合もあります)。丸みを帯びた数字を与えるだけのようですが:

 *** Download Progress Summary as of Wed May 13 12:57:11 2020 ***
=================================================================
[#b56779 1.7GiB/2.0GiB(86%) CN:1 DL:105MiB ETA:2s]
FILE: /work/blah.iso
-----------------------------------------------------------------
3
ilkkachu

やり方がある。

一致させたいのは、行の終わりのゼロ、この正規表現です。

\0*$

正規表現を実行するツールがNULバイト(\0)と\0 逃れる。 GNU PCRE正規表現を使用したgrepは、このように(-aはバイナリファイルを許可します、-o印刷o nly一致したセクション、-PはPCRE正規表現用です:

grep -aPo '\0*$' file

これにより、各行の最後にすべてのゼロバイト(および各改行)が出力されます。

最後の行だけを抽出するために、sed(NULを含むファイルで機能することが文書化されているGNU sedを使用できます(-zオプション))(一部のツールはNULバイトを好まない):

sed -n '$p' file | grep -aPo '\0*$'

実行する必要があるのはそれらを数えることだけです:

zerobytes=$(( $( sed -n '$p' file | grep -aPo '\0*$' | wc -c ) - 1 ))

もちろん、この時点で実行する必要があるのは、ダウンロードしたファイルのサイズを取得するために、ファイル全体の長さからその値を引くことだけです。

テストされていないコード

# alias ggrep and gdu to GNU grep and GNU du or install coreutils from Homebrew
filesize() {
    local filename="$1"
    test -e "$filename" || return 1

    local filesize="$(gdu -sb "$filename" | awk '{ print $1 }')"
    echo "$filesize"
}
filesizereal() {
    local file="$1"
    local zerobytes=$(( $( gsed -n '$p' "$file" | ggrep -aPo '\0*$' | wc -c ) - 1 ))
    echo "$(( ${$(filesize "$file"):-0} - $zerobytes ))"
}
1
Isaac

私はRust後続ゼロをカウントするスクリプトを書きました。かなり高速ですが、ファイル全体をロードします。これを参照してください 質問

このスクリプトを実行するには、システムにRustおよびscriptistoをインストールする必要があります。このスクリプトに名前を付けましたtrailingzeroes.rs私のシステム。

#!/usr/bin/env scriptisto

// scriptisto-begin
// script_src: src/main.rs
// build_cmd: cargo build --release
// target_bin: ./target/release/script
// files:
//  - path: Cargo.toml
//    content: |
//     package = { name = "script", version = "0.1.0", edition = "2018"}
//     [dependencies]
// scriptisto-end

// https://users.Rust-lang.org/t/count-trailing-zero-bytes-of-a-binary-file/42503/4

use std::env;
use std::fs;

fn main() {
    let filename = env::args().nth(1).unwrap();
    let buffer = fs::read(filename).unwrap();
    let count = buffer.iter().rev().take_while(|b| **b == 0).count();
    println!("{}", count);
}

さて、

# gdu is GNU du
# ggrep is GNU grep

function filesize() {
    # '<file> ; returns size in bytes.'

    local FILENAME="$1"
    test -e "$FILENAME" || { echo "File $FILENAME doesn't exist." >&2 ; return 1 }

    local SIZE="$(gdu -sb $FILENAME | awk '{ print $1 }')"
    ec $SIZE
}
function filesizereal() {
    local file="$1"
    test -e "$file" || { echo "File $file doesn't exist." >&2 ; return 1 }
    local zerobytes
    # zerobytes=$(( $( ggrep -aPo '\0*$' $file | wc -c ) - 1 ))
    zerobytes="${$(trailingzeroes.rs $file)}"
    echo $(( ${$(filesize $file):-0} - $zerobytes )) 
}
0
HappyFace