Не в формате GZIP — JAVA

Я пытаюсь записать сжатые данные в файл, а затем прочитать данные и распаковать их с помощью библиотеки GZIP. Я пытался изменить все форматирование на StandardCharsets.UTF-8 и ISO-8859-1, и ни один из них не исправил ошибку формата GZIP. Мне интересно, может ли это быть связано с файлом, который я читаю? Вот функция сжатия:

public static byte[] compress(String originalFile, String compressFile) throws IOException {

    // read in data from text file
    // The name of the file to open.
    String fileName = originalFile;

    // This will reference one line at a time
    String line = null;
    String original = "";

    try {
        // FileReader reads text files in the default encoding.
        FileReader fileReader = 
            new FileReader(fileName);

        // Always wrap FileReader in BufferedReader.
        BufferedReader bufferedReader = 
            new BufferedReader(fileReader);

        while((line = bufferedReader.readLine()) != null) {
            original.concat(line);
        }   

        // Always close files.
        bufferedReader.close();         
    }
    catch(FileNotFoundException ex) {
        System.out.println(
            "Unable to open file '" + 
            fileName + "'");                
    }
    catch(IOException ex) {
        System.out.println(
            "Error reading file '" 
            + fileName + "'");                  
        // Or we could just do this: 
        // ex.printStackTrace();
    }


    // create a new output stream for original string
    try (ByteArrayOutputStream out = new ByteArrayOutputStream())
    {
        try (GZIPOutputStream gzip = new GZIPOutputStream(out))
        {
            gzip.write(original.getBytes(StandardCharsets.UTF_8));
        }
        byte[] compressed = out.toByteArray();
        out.close();

        String compressedFileName = compressFile;

        try {
            // Assume default encoding.
            FileWriter fileWriter =
                new FileWriter(compressedFileName);

            // Always wrap FileWriter in BufferedWriter.
            BufferedWriter bufferedWriter =
                new BufferedWriter(fileWriter);

            // Note that write() does not automatically
            // append a newline character.
            String compressedStr = compressed.toString();
            bufferedWriter.write(compressedStr);

            // Always close files.
            bufferedWriter.close();
        }
        catch(IOException ex) {
            System.out.println(
                "Error writing to file '"
                + fileName + "'");
            // Or we could just do this:
            // ex.printStackTrace();
        }
        return compressed;
    }
}

(Я получаю сообщение об ошибке в следующей функции декомпрессии) -

GZIPInputStream compressedByteArrayStream = new GZIPInputStream(new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)));

Функция декомпрессии:

 public static String decompress(String file) throws IOException {

    byte[] compressed = {};
    String s = "";

    File fileName = new File(file);
    FileInputStream fin = null;
    try {
        // create FileInputStream object
        fin = new FileInputStream(fileName);

        // Reads up to certain bytes of data from this input stream into an array of bytes.
        fin.read(compressed);
        //create string from byte array
        s = new String(compressed);
        System.out.println("File content: " + s);
    }
    catch (FileNotFoundException e) {
        System.out.println("File not found" + e);
    }
    catch (IOException ioe) {
        System.out.println("Exception while reading file " + ioe);
    }
    finally {
        // close the streams using close method
        try {
            if (fin != null) {
                fin.close();
            }
        }
        catch (IOException ioe) {
            System.out.println("Error while closing stream: " + ioe);
        }
    }


    // create a new input string for compressed byte array
    GZIPInputStream compressedByteArrayStream = new GZIPInputStream(new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)));
    ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();

    byte[] buffer = new byte[8192];

    // create a string builder and byte reader for the compressed byte array
    BufferedReader decompressionBr = new BufferedReader(new InputStreamReader(compressedByteArrayStream, StandardCharsets.UTF_8));
    StringBuilder decompressionSb = new StringBuilder();

    // write data to decompressed string
    String line1;
    while((line1 = decompressionBr.readLine()) != null) {
        decompressionSb.append(line1);
    }
    decompressionBr.close();

    int len;
    String uncompressedStr = "";
    while((len = compressedByteArrayStream.read(buffer)) > 0) {
        uncompressedStr = byteOutput.toString();
    }

    compressedByteArrayStream.close();  
    return uncompressedStr;
}

Вот сообщение об ошибке, которое я получаю:

[B@7852e922
File content: 
java.io.EOFException
    at java.util.zip.GZIPInputStream.readUByte(GZIPInputStream.java:268)
    at java.util.zip.GZIPInputStream.readUShort(GZIPInputStream.java:258)
    at java.util.zip.GZIPInputStream.readHeader(GZIPInputStream.java:164)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:79)
    at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:91)
    at org.kingswoodoxford.Compression.decompress(Compression.java:136)
    at org.kingswoodoxford.Compression.main(Compression.java:183)

Любые предложения относительно того, как я могу это исправить?


person Trey Taylor    schedule 03.12.2015    source источник
comment
Ваш исходный файл действительно utf 8?   -  person Kalpesh Soni    schedule 03.12.2015
comment
Не преобразовывать в строку. В этом нет необходимости, и большинство наборов символов не будут обрабатывать все возможные байты. И если вы не используете строки, то нет необходимости использовать Reader и Writer; используйте InputStream и OutputStream.   -  person kdgregory    schedule 03.12.2015


Ответы (1)


Когда вы читаете файл, вы отбрасываете новую строку в конце каждой строки.

Более эффективным вариантом, который делает это, является копирование блока, т.е. char[] за раз. Вы также можете преобразовывать текст по ходу работы, а не создавать строку или байт[].

BTW original.concat(line); возвращает объединенную строку, которую вы отбрасываете.

Настоящая проблема в том, что вы пишете в один поток и закрываете другой. Это означает, что если в конце файла есть какие-то буферизованные данные (а это весьма вероятно), то конец файла будет обрезан и при чтении будет жаловаться, что ваш файл неполный или EOFException.

Вот более короткий пример

public static void compress(String originalFile, String compressFile) throws IOException {
    char[] buffer = new char[8192];
    try (
            FileReader reader = new FileReader(originalFile);
            Writer writer = new OutputStreamWriter(
                    new GZIPOutputStream(new FileOutputStream(compressFile)));
    ) {
        for (int len; (len = reader.read(buffer)) > 0; )
            writer.write(buffer, 0, len);
    }
}

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

person Peter Lawrey    schedule 03.12.2015
comment
Спасибо, поэтому я считаю, что решил проблему с закрытием потока, закрыв свой GZIPOutputStream, а также мой ByteArrayOutputStream. Что касается чтения файла, я не совсем уверен, как я отбрасываю новую строку в конце каждой строки и как я могу это исправить. - person Trey Taylor; 03.12.2015
comment
@TreyTaylor BufferedReader.readLine() не включает символы новой строки. Смотрите мой ответ о том, как вы должны это сделать. - person Peter Lawrey; 03.12.2015
comment
@TreyTaylor, если подумать об этом, вам действительно стоит чему-то научиться здесь, потому что вы, похоже, объединили почти все распространенные ошибки, о которых я могу думать. ;) Хотя вы не использовали StringBuffer по крайней мере ^_^ - person Peter Lawrey; 03.12.2015
comment
Извините, я новичок в Java. Но в любом случае я написал функцию, которая считывает сжатые данные в массив байтов, а затем распаковывает возвращенные сжатые данные и записывает распакованную строку. Всего около 60 строк, а не 250 :) - person Trey Taylor; 03.12.2015
comment
@TreyTaylor Эксперт - это тот, кто уже совершил все ошибки раньше. ;) - person Peter Lawrey; 03.12.2015