2014-02-19 7 views
0

Моя идея - сделать небольшое программное обеспечение, которое читает файл (который нельзя прочитать «естественно», но содержит некоторые изображения), превращает его данные в шестнадцатеричный, ищет PNG куски (вид меток, которые находятся в начале и конце файла .png), и сохраняет полученные данные в разных файлах (после получения их из шестнадцатеричного). Я делаю это в Java, используя такой код:Чтение и запись огромных файлов в java

// out is where to show the result and file is the source 
public static void hexDump(PrintStream out, File file) throws IOException { 
    InputStream is = new FileInputStream(file); 
    StringBuffer Buffer = new StringBuffer(); 

    while (is.available() > 0) { 
     StringBuilder sb1 = new StringBuilder(); 

     for (int j = 0; j < 16; j++) { 
      if (is.available() > 0) { 
       int value = (int) is.read(); 
       // transform the current data into hex 
       sb1.append(String.format("%02X ", value)); 
      } 
     } 

     Buffer.append(sb1); 

     // Should I look for the PNG here? I'm not sure 
    } 
    is.close(); 
    // Print the result in out (that may be the console or a file) 
    out.print(Buffer); 

} 

Я уверен, что есть еще способы сделать это, используя меньше «машину-ресурсы» при открытии больших файлов. Если у вас есть какие-либо идеи, пожалуйста, скажите мне. Благодаря!

Это первый раз, когда я отправляю сообщения, поэтому, если есть какие-либо ошибки, пожалуйста, помогите мне исправить.

+3

Какая проблема? Кроме того, преждевременная оптимизация - это корень всего зла - сначала создайте поддерживаемый код, ТОГДА оптимизируйте. – Smutje

+0

@Smutje Проблема в том, что я пробовал это на огромных файлах, и для копирования шестнадцатеричных данных в выходной файл требуется много времени. О поддерживаемом коде, что я должен улучшить здесь? Я новичок в программировании на Java – AlkTheShadow

+2

Зачем вам преобразовать весь файл в hex? Если вы знаете маркер PNG в шестнадцатеричном формате, затем преобразуйте его в двоичный файл, чтобы сравнить его непосредственно с файлом. –

ответ

0

Как говорит Эрвин Болвидт в комментариях, первое, что не нужно преобразовать в шестнадцатеричный. Если по какой-то причине вы должны преобразовать в hex, прекратите добавлять содержимое к двум буферам и всегда используете StringBuilder, а не StringBuffer. StringBuilder может быть на 3 раза быстрее, чем StringBuffer.

Кроме того, буферный файл читается с помощью BufferedReader. Чтение одного символа за раз с FileInputStream.read() происходит очень медленно.

0

Очень простой способ сделать это, вероятно, довольно быстро - прочитать весь файл в памяти (как двоичные данные, а не как шестнадцатеричный дамп), а затем выполнить поиск маркеров.

Это имеет два ограничения:

  • он обрабатывает только файлы размером до 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; 
    } 
} 

Я модифицировал этот последний кусок кода, чтобы сделать возможным, чтобы начать поиск на смещение, отличное от нуля.

0

Чтение Файл байта за один раз займет здесь значительное время. Вы можете улучшить это на порядок.Вы должны использовать DataInputStream вокруг BufferedInputStream вокруг FileInputStream, и чтение 16 байт одновременно с readFully.

А затем обрабатывать их, без преобразования и из шестнадцатеричной, что совсем не нужно здесь, и писать их выход (ы), как вы идете, через BufferedOutputStream вокруг FileOutputStream,, а не конкатенацию всего файла в память и необходимость писать все за один раз. Конечно, требует времени, но это потому, что это происходит не потому, что вам нужно это делать.

Смежные вопросы