
Ich suche nach einer Möglichkeit, eine Statistik über einen sehr großen Datenträger (um ein Vielfaches größer als der verfügbare Arbeitsspeicher) zu erhalten, der ausgibt, welche Bytewerte in den Dateien vorhanden sind und wie oft:
A0 01 00 FF 77 01 77 01 A0
Ich muss wissen, wie viele A0-Bytes in dieser Datei sind, wie viele 01-Bytes usw. Das Ergebnis könnte sein:
A0: 2
01: 3
00: 1
FF: 1
77: 2
Daher ist diese Frage sehr nah an der FrageWie zählt man die Anzahl der Bytes in einer Datei, indem man dieselben Bytes gruppiert?aber keine der vorhandenen Antworten funktioniert für größere Dateien. Meines Wissens nach erfordern alle Antworten einen Mindest-RAM, der der Größe der zu testenden Datei entspricht (bis zu einem Vielfachen).
Daher funktionieren die Antworten nicht auf Systemen mit kleinem RAM, z. B. einem Raspberry zur Verarbeitung einer mehrere GB großen Datei.
Gibt es eine einfache Lösung, die bei jeder Dateigröße funktioniert, selbst wenn uns beispielsweise nur 512 MB RAM zur Verfügung stehen?
Antwort1
Erstellen Sie ein kleines C-Programm (oder Perl-, Python- oder was auch immer-Programm), das ein Byte nach dem anderen liest und die Gesamtsumme speichert. Jede Sprache, die auf einem vernünftigen Betriebssystem nicht völlig hirntot ist, wird Pufferung und andere Aufgaben auf transparente und einigermaßen effiziente Weise erledigen.
Antwort2
Ich bin nicht sicher, ob das die Lösung ist, nach der Sie suchen, aber ich würde die Datei einfach in mehrere kleinere Dateien aufteilen (z. B. über split -b 100MB yourfile
), indem ich die im von Ihnen verlinkten Thread beschriebenen Methoden anwende und dann die gezählten Bytes in den einzelnen Dateien mit der Tabellenkalkulationssoftware Ihrer Wahl addiere.
Antwort3
Da es anscheinend kein vorhandenes Tool gibt, das das kann, was ich möchte, habe ich zwei selbst implementierte „Skripte“ in den Sprachen ausprobiert, die ich am besten beherrsche: Python und Java:
1. Versuch: Python
Das folgende Python 3-Skript funktioniert mit jeder Dateigröße und zählt, wie oft jedes Byte vorkommt. Leider funktioniert auch dieses Skript sehr, sehr langsam. Mit Python 3.5 auf einem Raspberry 2 dauert es mehr als eine Sekunde, um ein Megabyte zu verarbeiten!
#!/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))
2. Versuch: Java
Bei meinem zweiten Versuch habe ich Java verwendet und es scheint, dass eine statisch typisierte Sprache mit JIT, die Puffer wiederverwendet, viel effizienter funktioniert. Die Java-Version, die auf Java 9 lief, war 40-mal schneller als die Python-Version, obwohl beide Versionen gleich funktionierten.
- Kompilieren:
javac CountByteValues.java
- Laufen:
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();
}
}
}
Antwort4
Wie üblich wäre ein C-Programm am schnellsten.
Auf einem Computer, auf dem das von Ihnen vorgestellte Perl-Beispiel 5 Sekunden dauert,
dauert der nächste C-Code nur 0,069 Sekunden:
#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;
}