나는 출력 파일에 어떤 바이트 값이 얼마나 자주 나타나는지 매우 큰(사용 가능한 RAM보다 몇 배 더 큰) 통계를 얻을 수 있는 방법을 찾고 있습니다.
A0 01 00 FF 77 01 77 01 A0
이 파일에 A0 바이트가 몇 개 있는지, 01이 몇 개 있는지 등을 알아야 합니다. 결과는 다음과 같습니다.
A0: 2
01: 3
00: 1
FF: 1
77: 2
그래서 이 질문은 이 질문에 매우 가깝습니다.동일한 바이트를 그룹화하여 파일의 바이트 수를 계산하는 방법은 무엇입니까?그러나 기존 답변 중 어느 것도 더 큰 파일에 적용되지 않습니다. 내가 이해한 바에 따르면, 모든 답변에는 최소한 테스트 중인 파일 크기와 동일한 RAM이 필요합니다(최대 여러 번).
따라서 다중 GB 파일을 처리하는 데 사용되는 Raspberry와 같이 RAM이 더 작은 시스템에는 대답이 적용되지 않습니다.
RAM이 512MB만 있어도 모든 파일 크기를 처리할 수 있는 간단한 솔루션이 있습니까?
답변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
두 번째 시도에서는 버퍼를 재사용하고 보다 효율적으로 작동하는 JIT가 포함된 정적인 유형의 언어인 Java를 사용했습니다. 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;
}