Очень простой способ сделать это, вероятно, довольно быстро - прочитать весь файл в памяти (как двоичные данные, а не как шестнадцатеричный дамп), а затем выполнить поиск маркеров.
Это имеет два ограничения:
- он обрабатывает только файлы размером до 2 Гб в длину (Максимальный размер Java-массивов)
- требует больших кусков памяти - можно оптимизировать это с помощью ридера меньше куски, но что делает алгоритм более сложный
основной код, чтобы сделать это, как это:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
public class Png {
static final String PNG_MARKER_HEX = "abcdef"; // TODO: replace with real marker
static final byte[] PNG_MARKER = hexStringToByteArray(PNG_MARKER_HEX);
public void splitPngChunks(File file) throws IOException {
byte[] bytes = Files.readAllBytes(file.toPath());
int offset = KMPMatch.indexOf(bytes, 0, PNG_MARKER);
while (offset >= 0) {
int nextOffset = KMPMatch.indexOf(bytes, 0, PNG_MARKER);
if (nextOffset < 0) {
writePngChunk(bytes, offset, bytes.length - offset);
} else {
writePngChunk(bytes, offset, nextOffset - offset);
}
offset = nextOffset;
}
}
public void writePngChunk(byte[] bytes, int offset, int length) {
// TODO: implement - where do you want to write the chunks?
}
}
Я не уверен, как эти маркеры PNG работают точно, я полагаю, что они начинают раздел интересующих вас данных и что следующий маркер запускает следующий раздел данных.
В стандартном Java есть две вещи: код для преобразования шестнадцатеричной строки в массив байтов и код для поиска байтового массива внутри другого байтового массива. Оба могут быть найдены в различных библиотеках apache-commons, но я расскажу, что ответы на них отправлены на более ранние вопросы в StackOverflow. Вы можете скопировать эти стенограммы в класс Png, чтобы сделать вышеуказанный код.
Convert a string representation of a hex dump to a byte array using Java?
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for (int i = 0; i < len; i += 2) {
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
}
return data;
}
Searching for a sequence of Bytes in a Binary File with Java
/**
* Knuth-Morris-Pratt Algorithm for Pattern Matching
*/
static class KMPMatch {
/**
* Finds the first occurrence of the pattern in the text.
*/
public static int indexOf(byte[] data, int offset, byte[] pattern) {
int[] failure = computeFailure(pattern);
int j = 0;
if (data.length - offset <= 0)
return -1;
for (int i = offset; i < data.length; i++) {
while (j > 0 && pattern[j] != data[i]) {
j = failure[j - 1];
}
if (pattern[j] == data[i]) {
j++;
}
if (j == pattern.length) {
return i - pattern.length + 1;
}
}
return -1;
}
/**
* Computes the failure function using a boot-strapping process, where the pattern is matched against itself.
*/
private static int[] computeFailure(byte[] pattern) {
int[] failure = new int[pattern.length];
int j = 0;
for (int i = 1; i < pattern.length; i++) {
while (j > 0 && pattern[j] != pattern[i]) {
j = failure[j - 1];
}
if (pattern[j] == pattern[i]) {
j++;
}
failure[i] = j;
}
return failure;
}
}
Я модифицировал этот последний кусок кода, чтобы сделать возможным, чтобы начать поиск на смещение, отличное от нуля.
Какая проблема? Кроме того, преждевременная оптимизация - это корень всего зла - сначала создайте поддерживаемый код, ТОГДА оптимизируйте. – Smutje
@Smutje Проблема в том, что я пробовал это на огромных файлах, и для копирования шестнадцатеричных данных в выходной файл требуется много времени. О поддерживаемом коде, что я должен улучшить здесь? Я новичок в программировании на Java – AlkTheShadow
Зачем вам преобразовать весь файл в hex? Если вы знаете маркер PNG в шестнадцатеричном формате, затем преобразуйте его в двоичный файл, чтобы сравнить его непосредственно с файлом. –