Zlib 压缩 在 Java 中使用 Deflate 和 Inflate 类

发布于 2024-11-10 03:49:26 字数 2460 浏览 5 评论 0原文

我想尝试使用 java.util.zip 中的 Deflate 和 Inflate 类进行 zlib 压缩。

我可以使用 Deflate 压缩代码,但在解压缩时出现此错误 -

Exception in thread "main" java.util.zip.DataFormatException: unknown compression method
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:238)
    at java.util.zip.Inflater.inflate(Inflater.java:256)
    at zlibCompression.main(zlibCompression.java:53)

这是迄今为止我的代码 -

import java.util.zip.*;
import java.io.*;

public class zlibCompression {

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException, DataFormatException {
        // TODO Auto-generated method stub

        String fname = "book1";
        FileReader infile = new FileReader(fname);
        BufferedReader in = new BufferedReader(infile);

        FileOutputStream out = new FileOutputStream("book1out.dfl");
        //BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));

        Deflater compress = new Deflater();
        Inflater decompress = new Inflater();

        String readFile = in.readLine();
        byte[] bx = readFile.getBytes();

        while(readFile!=null){
            byte[] input = readFile.getBytes();
            byte[] compressedData = new byte[1024];
            compress.setInput(input);
            compress.finish();
            int compressLength = compress.deflate(compressedData, 0, compressedData.length);
            //System.out.println(compressedData);
            out.write(compressedData, 0, compressLength);
            readFile = in.readLine();
        }

        File abc = new File("book1out.dfl");
        InputStream is = new FileInputStream("book1out.dfl");

        InflaterInputStream infl = new InflaterInputStream(new FileInputStream("book1out.dfl"), new Inflater());
        FileOutputStream outFile = new FileOutputStream("decompressed.txt");

        byte[] b = new byte[1024];
        while(true){

            int a = infl.read(b,0,1024);
            if(a==0)
                break;

            decompress.setInput(b);
            byte[] fresult = new byte[1024];
            //decompress.in
            int resLength = decompress.inflate(fresult);
            //outFile.write(b,0,1);
            //String outt = new String(fresult, 0, resLength);
            //System.out.println(outt);
        }

        System.out.println("complete");

    }
}

I want trying to use the Deflate and Inflate classes in java.util.zip for zlib compression.

I am able to compress the code using Deflate, but while decompressing, I am having this error -

Exception in thread "main" java.util.zip.DataFormatException: unknown compression method
    at java.util.zip.Inflater.inflateBytes(Native Method)
    at java.util.zip.Inflater.inflate(Inflater.java:238)
    at java.util.zip.Inflater.inflate(Inflater.java:256)
    at zlibCompression.main(zlibCompression.java:53)

Here is my code so far -

import java.util.zip.*;
import java.io.*;

public class zlibCompression {

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException, DataFormatException {
        // TODO Auto-generated method stub

        String fname = "book1";
        FileReader infile = new FileReader(fname);
        BufferedReader in = new BufferedReader(infile);

        FileOutputStream out = new FileOutputStream("book1out.dfl");
        //BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));

        Deflater compress = new Deflater();
        Inflater decompress = new Inflater();

        String readFile = in.readLine();
        byte[] bx = readFile.getBytes();

        while(readFile!=null){
            byte[] input = readFile.getBytes();
            byte[] compressedData = new byte[1024];
            compress.setInput(input);
            compress.finish();
            int compressLength = compress.deflate(compressedData, 0, compressedData.length);
            //System.out.println(compressedData);
            out.write(compressedData, 0, compressLength);
            readFile = in.readLine();
        }

        File abc = new File("book1out.dfl");
        InputStream is = new FileInputStream("book1out.dfl");

        InflaterInputStream infl = new InflaterInputStream(new FileInputStream("book1out.dfl"), new Inflater());
        FileOutputStream outFile = new FileOutputStream("decompressed.txt");

        byte[] b = new byte[1024];
        while(true){

            int a = infl.read(b,0,1024);
            if(a==0)
                break;

            decompress.setInput(b);
            byte[] fresult = new byte[1024];
            //decompress.in
            int resLength = decompress.inflate(fresult);
            //outFile.write(b,0,1);
            //String outt = new String(fresult, 0, resLength);
            //System.out.println(outt);
        }

        System.out.println("complete");

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

薯片软お妹 2024-11-17 03:49:26

你想在这里做什么?您使用 InflaterInputStream 来解压缩您的数据,然后您尝试再次将此解压缩的数据传递给 Inflater?使用其中之一,但不能同时使用两者。

这就是导致您出现异常的原因。

除此之外,还有相当多的小错误,比如bestsss提到的这些:

  • 你在循环中完成了压缩 - 完成后,无法添加更多数据。
  • 您不会检查 deflate 过程产生了多少输出。如果行很长,则可能会超过 1024 字节。
  • 您也可以在不设置长度 a 的情况下设置 Inflater 的输入。

我发现的更多内容:

  • 在写入后(以及从同一文件读取之前),您不会关闭 FileOutputStream。
  • 您使用 readLine() 读取一行文本,但随后您不再添加换行符,这意味着解压后的文件中不会有任何换行符。
  • 您无需任何必要即可从字节转换为字符串,然后再次转换为字节。
  • 您创建稍后不会使用的变量。

我不会尝试纠正你的程序。这是一个简单的方法,它使用 DeflaterOutputStream 和 InflaterInputStream 完成我认为您想要的操作。 (您也可以使用 JZlib 的 ZInputStream 和 ZOutputStream 来代替。)

import java.util.zip.*;
import java.io.*;

/**
 * Example program to demonstrate how to use zlib compression with
 * Java.
 * Inspired by http://stackoverflow.com/q/6173920/600500.
 */
public class ZlibCompression {

    /**
     * Compresses a file with zlib compression.
     */
    public static void compressFile(File raw, File compressed)
        throws IOException
    {
        InputStream in = new FileInputStream(raw);
        OutputStream out =
            new DeflaterOutputStream(new FileOutputStream(compressed));
        shovelInToOut(in, out);
        in.close();
        out.close();
    }

    /**
     * Decompresses a zlib compressed file.
     */
    public static void decompressFile(File compressed, File raw)
        throws IOException
    {
        InputStream in =
            new InflaterInputStream(new FileInputStream(compressed));
        OutputStream out = new FileOutputStream(raw);
        shovelInToOut(in, out);
        in.close();
        out.close();
    }

    /**
     * Shovels all data from an input stream to an output stream.
     */
    private static void shovelInToOut(InputStream in, OutputStream out)
        throws IOException
    {
        byte[] buffer = new byte[1000];
        int len;
        while((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }


    /**
     * Main method to test it all.
     */
    public static void main(String[] args) throws IOException, DataFormatException {
        File compressed = new File("book1out.dfl");
        compressFile(new File("book1"), compressed);
        decompressFile(compressed, new File("decompressed.txt"));
    }
}

为了提高效率,用缓冲流包装文件流可能会很有用。如果这对性能至关重要,请对其进行测量。

What are you trying to do here? You use an InflaterInputStream, which decompresses your data, and then you try to pass this decompressed data again to an Inflater? Use either one of them, but not both.

This is what is causing your exception here.

In addition to this, there are quite some minor errors, like these mentioned by bestsss:

  • You finish the compression in the loop - after finishing, no more data can be added.
  • You don't check how much output the deflate process produces. If you have long lines, it could be more than 1024 bytes.
  • You set input to the Inflater without setting the length a, too.

Some more which I found:

  • You don't close your FileOutputStream after writing (and before reading from the same file).
  • You use readLine() to read a line of text, but then you don't add the line break again, which means in your decompressed file won't be any line breaks.
  • You convert from bytes to string and to bytes again without any need.
  • You create variables which you don't use later on.

I won't try to correct your program. Here is a simple one which does what I think you want, using DeflaterOutputStream and InflaterInputStream. (You could also use JZlib's ZInputStream and ZOutputStream instead.)

import java.util.zip.*;
import java.io.*;

/**
 * Example program to demonstrate how to use zlib compression with
 * Java.
 * Inspired by http://stackoverflow.com/q/6173920/600500.
 */
public class ZlibCompression {

    /**
     * Compresses a file with zlib compression.
     */
    public static void compressFile(File raw, File compressed)
        throws IOException
    {
        InputStream in = new FileInputStream(raw);
        OutputStream out =
            new DeflaterOutputStream(new FileOutputStream(compressed));
        shovelInToOut(in, out);
        in.close();
        out.close();
    }

    /**
     * Decompresses a zlib compressed file.
     */
    public static void decompressFile(File compressed, File raw)
        throws IOException
    {
        InputStream in =
            new InflaterInputStream(new FileInputStream(compressed));
        OutputStream out = new FileOutputStream(raw);
        shovelInToOut(in, out);
        in.close();
        out.close();
    }

    /**
     * Shovels all data from an input stream to an output stream.
     */
    private static void shovelInToOut(InputStream in, OutputStream out)
        throws IOException
    {
        byte[] buffer = new byte[1000];
        int len;
        while((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }


    /**
     * Main method to test it all.
     */
    public static void main(String[] args) throws IOException, DataFormatException {
        File compressed = new File("book1out.dfl");
        compressFile(new File("book1"), compressed);
        decompressFile(compressed, new File("decompressed.txt"));
    }
}

For more efficiency, it might be useful to wrap the file streams with buffered streams. If this is performance critical, measure it.

最舍不得你 2024-11-17 03:49:26

Paŭlo Ebermann 的代码可以通过使用 try-with-resources

import java.util.Scanner;
import java.util.zip.*;
import java.io.*;

public class ZLibCompression
{
    public static void compress(File raw, File compressed) throws IOException
    {
        try (InputStream inputStream = new FileInputStream(raw);
             OutputStream outputStream = new DeflaterOutputStream(new FileOutputStream(compressed)))
        {
            copy(inputStream, outputStream);
        }
    }

    public static void decompress(File compressed, File raw)
            throws IOException
    {
        try (InputStream inputStream = new InflaterInputStream(new FileInputStream(compressed));
             OutputStream outputStream = new FileOutputStream(raw))
        {
            copy(inputStream, outputStream);
        }
    }

    public static String decompress(File compressed) throws IOException
    {
        try (InputStream inputStream = new InflaterInputStream(new FileInputStream(compressed)))
        {
            return toString(inputStream);
        }
    }

    private static String toString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }

    private static void copy(InputStream inputStream, OutputStream outputStream)
            throws IOException
    {
        byte[] buffer = new byte[1000];
        int length;

        while ((length = inputStream.read(buffer)) > 0)
        {
            outputStream.write(buffer, 0, length);
        }
    }
}

使用 Zlib 的另一种方式确实是使用 InflaterDeflater 类:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import static java.util.zip.Deflater.BEST_COMPRESSION;

public class CompressionUtils
{
    private static final int BUFFER_SIZE = 1024;

    public static byte[] compress(final byte[] data) throws IOException
    {
        final Deflater deflater = new Deflater();
        deflater.setLevel(BEST_COMPRESSION);
        deflater.setInput(data);

        try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length))
        {
            deflater.finish();
            final byte[] buffer = new byte[BUFFER_SIZE];
            while (!deflater.finished())
            {
                final int count = deflater.deflate(buffer);
                outputStream.write(buffer, 0, count);
            }

            return outputStream.toByteArray();
        }
    }

    public static byte[] decompress(final byte[] data) throws Exception
    {
        final Inflater inflater = new Inflater();
        inflater.setInput(data);

        try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length))
        {
            byte[] buffer = new byte[BUFFER_SIZE];
            while (!inflater.finished())
            {
                final int count = inflater.inflate(buffer);
                outputStream.write(buffer, 0, count);
            }

            return outputStream.toByteArray();
        }
    }
}

Paŭlo Ebermann's code can be further improved by using try-with-resources:

import java.util.Scanner;
import java.util.zip.*;
import java.io.*;

public class ZLibCompression
{
    public static void compress(File raw, File compressed) throws IOException
    {
        try (InputStream inputStream = new FileInputStream(raw);
             OutputStream outputStream = new DeflaterOutputStream(new FileOutputStream(compressed)))
        {
            copy(inputStream, outputStream);
        }
    }

    public static void decompress(File compressed, File raw)
            throws IOException
    {
        try (InputStream inputStream = new InflaterInputStream(new FileInputStream(compressed));
             OutputStream outputStream = new FileOutputStream(raw))
        {
            copy(inputStream, outputStream);
        }
    }

    public static String decompress(File compressed) throws IOException
    {
        try (InputStream inputStream = new InflaterInputStream(new FileInputStream(compressed)))
        {
            return toString(inputStream);
        }
    }

    private static String toString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }

    private static void copy(InputStream inputStream, OutputStream outputStream)
            throws IOException
    {
        byte[] buffer = new byte[1000];
        int length;

        while ((length = inputStream.read(buffer)) > 0)
        {
            outputStream.write(buffer, 0, length);
        }
    }
}

Also another way of using Zlib is indeed with the Inflater and Deflater classes:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import static java.util.zip.Deflater.BEST_COMPRESSION;

public class CompressionUtils
{
    private static final int BUFFER_SIZE = 1024;

    public static byte[] compress(final byte[] data) throws IOException
    {
        final Deflater deflater = new Deflater();
        deflater.setLevel(BEST_COMPRESSION);
        deflater.setInput(data);

        try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length))
        {
            deflater.finish();
            final byte[] buffer = new byte[BUFFER_SIZE];
            while (!deflater.finished())
            {
                final int count = deflater.deflate(buffer);
                outputStream.write(buffer, 0, count);
            }

            return outputStream.toByteArray();
        }
    }

    public static byte[] decompress(final byte[] data) throws Exception
    {
        final Inflater inflater = new Inflater();
        inflater.setInput(data);

        try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length))
        {
            byte[] buffer = new byte[BUFFER_SIZE];
            while (!inflater.finished())
            {
                final int count = inflater.inflate(buffer);
                outputStream.write(buffer, 0, count);
            }

            return outputStream.toByteArray();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文