후행 0바이트를 제외한 파일 크기 가져오기

후행 0바이트를 제외한 파일 크기 가져오기

다운로드 중인 파일의 크기를 알고 싶습니다. 파일이 사전 할당되었으므로 를 사용하면 du -sd최종 전체 크기만 반환됩니다. 나는 얼마나 많이 다운로드되었는지 알고 싶기 때문에 뒤에 오는 0바이트가 계산되는 것을 원하지 않습니다. 이 사이즈는 어떻게 구하나요?

aria2c이는 중지된 다운로드를 쉽게 재개할 수 있고 다운로드 길이를 저장하지 않는 것 같기 때문에 가능합니다.해당 제어(세션) 파일. 나는 썼다스크립트total_length.aria2제어 파일 에서 읽습니다. 하지만 이는 다운로드 길이가 아닌 전체 길이입니다. 이 스크립트를 쉽게 사용할 수 있으며기술 사양aria2 스토어의 다른 속성을 가져옵니다.

댓글 업데이트:

ilkkachu가 암시했듯이 .aria2 파일의 BITFIELD는 실제로 맵인 것 같습니다. 각 비트는 파일 블록에 해당하며 1은 "다운로드됨"을 의미하고 0은 "다운로드되지 않음"을 의미합니다. 비트 필드 길이는 블록 수를 나타냅니다(블록 크기는 파일 크기를 블록 번호로 나눈 것일 수 있음). 다운로드 진행률은 BITFIELD의 청크 수에 대한 1초의 비율로 제공된다고 확신합니다. 안타깝게도 AFAICT, .aria2 파일은 지연 후 또는 다운로드가 중단된 후 즉시 업데이트되는 것 같습니다.

답변1

다운로드 진행 상황을 아는 문제만 고려하면 aria2몇 가지 옵션이 있습니다.

설명에서 설명한 대로 이 정보는 filename.aria2제어 파일( )의 비트맵에 있습니다. 에 기록되어 있어요https://aria2.github.io/manual/en/html/technical-notes.html. HTTP 다운로드는 처음부터 선형적이기 때문에 비트맵을 갖는 것은 HTTP 다운로드에 그다지 의미가 없지만 BitTorrent 다운로드 등에 대해서는 더 의미가 있다고 생각합니다.

다음은 다운로드한 특정 제어 파일의 16진수 덤프이며, 중요한 필드는 ( od -tx1 file.aria2)로 표시되어 있습니다.

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

비트맵에 설정된 비트 수를 세어 보면 1MiB(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
-----------------------------------------------------------------

답변2

방법이 있습니다.

일치시키려는 것은 줄 끝의 0입니다. 이 정규식은 다음과 같습니다.

\0*$

정규식을 실행하는 도구가 \0NUL 바이트( )를 차단 하지 않고 \0이스케이프를 이해하는 경우 이 값은 일치됩니다. PCRE 정규 표현식을 사용하는 GNU grep은 이 작업을 수행합니다( -a바이너리 허용, -o인쇄일치하는 부분만 -PPCRE 정규식에 적용됩니다.)

grep -aPo '\0*$' file

그러면 각 줄의 끝에 모두 0바이트가 출력됩니다(각 줄 바꿈 문자 포함).

마지막 줄만 추출하려면 sed를 사용할 수 있습니다(GNU sed는 NUL이 포함된 파일을 처리하는 것으로 문서화되어 있습니다(이 -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 ))"
}

답변3

나는 후행 0을 계산하는 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 )) 
}

관련 정보