동일한 바이트를 그룹화하여 매우 큰 파일의 바이트 수를 계산하는 방법은 무엇입니까?

동일한 바이트를 그룹화하여 매우 큰 파일의 바이트 수를 계산하는 방법은 무엇입니까?

매우 큰(사용 가능한 RAM보다 몇 배 더 큰) 출력에 대한 통계를 얻는 방법을 찾고 있습니다. 파일에 어떤 바이트 값이 있고 얼마나 자주 있는지 출력됩니다.

A0 01 00 FF 77 01 77 01 A0

이 파일에 A0 바이트가 몇 개 있는지, 01이 몇 개 있는지 등을 알아야 합니다. 결과는 다음과 같습니다.

A0: 2
01: 3
00: 1
FF: 1
77: 2

따라서 이 질문은 질문에 매우 가깝습니다.동일한 바이트를 그룹화하여 파일의 바이트 수를 계산하는 방법은 무엇입니까?그러나 기존 답변 중 더 큰 파일에는 작동하지 않습니다. 내 이해에 따르면 모든 답변에는 테스트할 파일 크기와 동일한 최소 RAM이 필요합니다(최대 여러 번).

따라서 작은 RAM이 있는 시스템(예: 다중 GB 파일 처리용 Raspberry)에서는 답변이 작동하지 않습니다.

예를 들어 512MB RAM만 사용할 수 있는 경우에도 모든 파일 크기에서 작동하는 간단한 솔루션이 있습니까?

답변1

한 번에 1바이트씩 읽고 총계를 유지하는 작은 C(또는 Perl, Python 등) 프로그램을 만들어 보세요. 합리적인 운영 체제에서 완전히 브레인데드되지 않은 모든 언어는 버퍼링 및 기타 집안일을 합리적으로 효율적인 방식으로 투명하게 처리합니다.

답변2

그것이 당신이 찾고 있는 해결책인지는 확실하지 않지만 split -b 100MB yourfile링크한 스레드에 설명된 방법을 적용하여 파일을 여러 개의 작은 파일(예: 를 통해)로 분할한 다음 스프레드시트를 사용하여 별도의 파일에 계산된 바이트를 추가할 것입니다. 당신이 선택한 소프트웨어.

답변3

내가 원하는 것을 수행할 수 있는 기존 도구가 없는 것 같아서 내가 가장 잘하는 언어인 Python과 Java를 사용하여 두 가지 자체 구현 "스크립트"를 시도했습니다.

첫 번째 시도: Python

다음 Python 3 스크립트는 모든 파일 크기에서 작동하며 각 바이트가 발생하는 빈도를 계산합니다. 불행히도 그것은 매우 느리게 작동합니다. Raspberry 2에서 Python 3.5를 사용하면 1MB를 처리하는 데 1초 이상이 필요합니다!

#!/usr/bin/python3
import sys
file_name = sys.argv[1]
count = 0
block_size = 1048576
byte_count = [0] * 256
with open(file_name, "rb") as f:
    data = f.read(block_size)
    while data:
        for b in data:
            byte_count[b] += 1
        count = count + len(data)
        print("%d MiB"%(count / 1048576))
        data = f.read(block_size)

print("read bytes: {}".format(count))
for i in range(0,255):
    b_c = byte_count[i]
    print("{} : {} ({:f} %)".format('0x%02x'%i, b_c,  b_c / count * 100))

두 번째 시도: Java

두 번째 시도에서는 Java를 사용했는데 버퍼를 재사용하는 JIT가 포함된 정적 유형 언어가 훨씬 더 효율적으로 작동하는 것 같습니다. Java 9에서 실행되는 Java 버전은 두 버전이 모두 동일한 방식으로 작동함에도 불구하고 Python 버전보다 40배 더 빨랐습니다.

  • 엮다:javac CountByteValues.java
  • 달리다:java -cp . CountByteValues <filename>

.

// CountByteValues.java
import java.io.FileInputStream;
import java.io.IOException;

public class CountByteValues {

    public static void main(String[] args) {
        try (FileInputStream in = new FileInputStream(args[0])) {
            long[] byteCount = new long[256];
            byte[] buffer = new byte[1048576];
            int read;
            long count = 0;
            while ((read = in.read(buffer)) >= 0) {
                for (int i = 0; i < read; i++) {
                    byteCount[0xFF & buffer[i]]++;
                }
                count += read;
                System.out.println((count / 1048576) + " MB");
            }

            System.out.println("Bytes read: " + count);
            for (int i = 0; i < byteCount.length; i++) {
                System.out.println(String.format("0x%x %d (%.2f%%)", i, byteCount[i], byteCount[i] * 100f / count));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

답변4

평소와 마찬가지로 C 프로그램이 가장 빠릅니다.
당신이 제시한 Perl 예제가 컴퓨터에서는 5초가 걸립니다.
다음 C 코드는 0.069초만 걸립니다.

#include <stdio.h>

#define BUFFERLEN 4096

int main(){
    // This program reads standard input and calculate frequencies of different
    // bytes and present the frequences for each byte value upon exit.
    //
    // Example:
    //
    //     $ echo "Hello world" | ./a.out
    //
    // Copyright (c) 2015 Björn Dahlgren
    // Open source: MIT License

    long long tot = 0; // long long guaranteed to be 64 bits i.e. 16 exabyte
    long long n[256]; // One byte == 8 bits => 256 unique bytes

    const int bufferlen = BUFFERLEN;
    char buffer[BUFFERLEN];
    int i;
    size_t nread;

    for (i=0; i<256; ++i)
        n[i] = 0;

    do {
        nread = fread(buffer, 1, bufferlen, stdin);
        for (i = 0; i < nread; ++i)
            ++n[(unsigned char)buffer[i]];
        tot += nread;
    } while (nread == bufferlen);
    // here you may want to inspect ferror of feof

    for (i=0; i<256; ++i){
        printf("%d ", i);
        printf("%f\n", n[i]/(float)tot);
    }
    return 0;
}

복사한 곳https://unix.stackexchange.com/a/209786/232326

관련 정보