java 实现.Z解压(代码是忘记在哪里找到的,自己整合了一下)

import java.io.*;


public class ZDecodes extends FilterInputStream {


    /**
     * @param is the input stream to decompress
     * @exception IOException if the header is malformed
     */
    public ZDecodes(InputStream is)  throws IOException
    {
        super(is);
        parse_header();
    }


    byte[] one = new byte[1];
    public synchronized int read() throws IOException
    {
        int b = in.read(one, 0, 1);
        if (b == 1)
            return (one[0] & 0xff);
        else
            return -1;
    }


    // string table stuff
    private static final int TBL_CLEAR = 0x100;
    private static final int TBL_FIRST = TBL_CLEAR + 1;

    private int[]  tab_prefix;
    private byte[] tab_suffix;
    private int[]  zeros = new int[256];
    private byte[] stack;

    // various state
    private boolean block_mode;
    private int  n_bits;
    private int  maxbits;
    private int  maxmaxcode;
    private int  maxcode;
    private int  bitmask;
    private int  oldcode;
    private byte finchar;
    private int  stackp;
    private int  free_ent;

    // input buffer
    private byte[]  data = new byte[10000];
    private int     bit_pos = 0, end = 0, got = 0;
    private boolean eof  = false;
    private static final int EXTRA = 64;


    public synchronized int read(byte[] buf, int off, int len)
            throws IOException
    {
        if (eof)  return -1;
        int start = off;

	/* Using local copies of various variables speeds things up by as
	 * much as 30% !
	 */
        int[]  l_tab_prefix = tab_prefix;
        byte[] l_tab_suffix = tab_suffix;
        byte[] l_stack      = stack;
        int    l_n_bits     = n_bits;
        int    l_maxcode    = maxcode;
        int    l_maxmaxcode = maxmaxcode;
        int    l_bitmask    = bitmask;
        int    l_oldcode    = oldcode;
        byte   l_finchar    = finchar;
        int    l_stackp     = stackp;
        int    l_free_ent   = free_ent;
        byte[] l_data       = data;
        int    l_bit_pos    = bit_pos;


        // empty stack if stuff still left

        int s_size = l_stack.length - l_stackp;
        if (s_size > 0)
        {
            int num = (s_size >= len) ? len : s_size ;
            System.arraycopy(l_stack, l_stackp, buf, off, num);
            off += num;
            len -= num;
            l_stackp += num;
        }

        if (len == 0)
        {
            stackp = l_stackp;
            return off-start;
        }


        // loop, filling local buffer until enough data has been decompressed

        main_loop: do
        {
            if (end < EXTRA)  fill();

            int bit_in = (got > 0) ? (end - end%l_n_bits)<<3 :
                    (end<<3)-(l_n_bits-1);

            while (l_bit_pos < bit_in)
            {
                // check for code-width expansion

                if (l_free_ent > l_maxcode)
                {
                    int n_bytes = l_n_bits << 3;
                    l_bit_pos = (l_bit_pos-1) +
                            n_bytes - (l_bit_pos-1+n_bytes) % n_bytes;

                    l_n_bits++;
                    l_maxcode = (l_n_bits==maxbits) ? l_maxmaxcode :
                            (1<<l_n_bits) - 1;

                    if (debug)
                        System.err.println("Code-width expanded to " + l_n_bits);

                    l_bitmask = (1<<l_n_bits)-1;
                    l_bit_pos = resetbuf(l_bit_pos);
                    continue main_loop;
                }


                // read next code

                int pos = l_bit_pos>>3;
                int code = (((l_data[pos]&0xFF) | ((l_data[pos+1]&0xFF)<<8) |
                        ((l_data[pos+2]&0xFF)<<16))
                        >> (l_bit_pos & 0x7)) & l_bitmask;
                l_bit_pos += l_n_bits;


                // handle first iteration

                if (l_oldcode == -1)
                {
                    if (code >= 256)
                        throw new IOException("corrupt input: " + code +
                                " > 255");
                    l_finchar = (byte) (l_oldcode = code);
                    buf[off++] = l_finchar;
                    len--;
                    continue;
                }


                // handle CLEAR code

                if (code == TBL_CLEAR && block_mode)
                {
                    System.arraycopy(zeros, 0, l_tab_prefix, 0, zeros.length);
                    l_free_ent = TBL_FIRST - 1;

                    int n_bytes = l_n_bits << 3;
                    l_bit_pos = (l_bit_pos-1) +
                            n_bytes - (l_bit_pos-1+n_bytes) % n_bytes;
                    l_n_bits  = INIT_BITS;
                    l_maxcode = (1 << l_n_bits) - 1;
                    l_bitmask = l_maxcode;

                    if (debug)  System.err.println("Code tables reset");

                    l_bit_pos = resetbuf(l_bit_pos);
                    continue main_loop;
                }


                // setup

                int incode = code;
                l_stackp = l_stack.length;


                // Handle KwK case

                if (code >= l_free_ent)
                {
                    if (code > l_free_ent)
                        throw new IOException("corrupt input: code=" + code +
                                ", free_ent=" + l_free_ent);

                    l_stack[--l_stackp] = l_finchar;
                    code = l_oldcode;
                }


                // Generate output characters in reverse order

                while (code >= 256)
                {
                    l_stack[--l_stackp] = l_tab_suffix[code];
                    code = l_tab_prefix[code];
                }
                l_finchar  = l_tab_suffix[code];
                buf[off++] = l_finchar;
                len--;


                // And put them out in forward order

                s_size = l_stack.length - l_stackp;
                int num = (s_size >= len) ? len : s_size ;
                System.arraycopy(l_stack, l_stackp, buf, off, num);
                off += num;
                len -= num;
                l_stackp += num;


                // generate new entry in table

                if (l_free_ent < l_maxmaxcode)
                {
                    l_tab_prefix[l_free_ent] = l_oldcode;
                    l_tab_suffix[l_free_ent] = l_finchar;
                    l_free_ent++;
                }


                // Remember previous code

                l_oldcode = incode;


                // if output buffer full, then return

                if (len == 0)
                {
                    n_bits   = l_n_bits;
                    maxcode  = l_maxcode;
                    bitmask  = l_bitmask;
                    oldcode  = l_oldcode;
                    finchar  = l_finchar;
                    stackp   = l_stackp;
                    free_ent = l_free_ent;
                    bit_pos  = l_bit_pos;

                    return off-start;
                }
            }

            l_bit_pos = resetbuf(l_bit_pos);
        } while (got > 0);

        n_bits   = l_n_bits;
        maxcode  = l_maxcode;
        bitmask  = l_bitmask;
        oldcode  = l_oldcode;
        finchar  = l_finchar;
        stackp   = l_stackp;
        free_ent = l_free_ent;
        bit_pos  = l_bit_pos;

        eof = true;
        return off-start;
    }


    /**
     * Moves the unread data in the buffer to the beginning and resets
     * the pointers.
     */
    private final int resetbuf(int bit_pos)
    {
        int pos = bit_pos >> 3;
        System.arraycopy(data, pos, data, 0, end-pos);
        end -= pos;
        return 0;
    }


    private final void fill()  throws IOException
    {
        got = in.read(data, end, data.length-1-end);
        if (got > 0)  end += got;
    }


    public synchronized long skip(long num)  throws IOException
    {
        byte[] tmp = new byte[(int) num];
        int got = read(tmp, 0, (int) num);

        if (got > 0)
            return (long) got;
        else
            return 0L;
    }


    public synchronized int available()  throws IOException
    {
        if (eof)  return 0;

        return in.available();
    }


    private static final int LZW_MAGIC		= 0x1f9d;
    private static final int MAX_BITS		= 16;
    private static final int INIT_BITS		= 9;
    private static final int HDR_MAXBITS 	= 0x1f;
    private static final int HDR_EXTENDED	= 0x20;
    private static final int HDR_FREE     	= 0x40;
    private static final int HDR_BLOCK_MODE	= 0x80;

    private void parse_header()  throws IOException
    {
        // read in and check magic number

        int t = in.read();
        if (t < 0)  throw new EOFException("Failed to read magic number");
        int magic = (t & 0xff) << 8;
        t = in.read();
        if (t < 0)  throw new EOFException("Failed to read magic number");
        magic += t & 0xff;
        if (magic != LZW_MAGIC)
            throw new IOException("Input not in compress format (read " +
                    "magic number 0x" +
                    Integer.toHexString(magic) + ")");


        // read in header byte

        int header = in.read();
        if (header < 0)  throw new EOFException("Failed to read header");

        block_mode = (header & HDR_BLOCK_MODE) > 0;
        maxbits    = header & HDR_MAXBITS;

        if (maxbits > MAX_BITS)
            throw new IOException("Stream compressed with " + maxbits +
                    " bits, but can only handle " + MAX_BITS +
                    " bits");

        if ((header & HDR_EXTENDED) > 0)
            throw new IOException("Header extension bit set");

        if ((header & HDR_FREE) > 0)
            throw new IOException("Header bit 6 set");

        if (debug)
        {
            System.err.println("block mode: " + block_mode);
            System.err.println("max bits:   " + maxbits);
        }


        // initialize stuff

        maxmaxcode = 1 << maxbits;
        n_bits     = INIT_BITS;
        maxcode    = (1 << n_bits) - 1;
        bitmask    = maxcode;
        oldcode    = -1;
        finchar    = 0;
        free_ent   = block_mode ? TBL_FIRST : 256;

        tab_prefix = new int[1 << maxbits];
        tab_suffix = new byte[1 << maxbits];
        stack      = new byte[1 << maxbits];
        stackp     = stack.length;

        for (int idx=255; idx>=0; idx--)
            tab_suffix[idx] = (byte) idx;
    }


    private static final boolean debug = false;

    public static void ZDecodes(String zPath, String oPath) throws Exception{
        ZDecodes(zPath,oPath,true);
    }

    public static void ZDecodes(String zPath, String oPath,boolean isNeedDelSrc) throws Exception{
        OutputStream outputStream = null;
        InputStream in = null;
        try {
            File file = new File(oPath); //解压后的存放路径
            if (!file.exists()) file.createNewFile();
            outputStream = new FileOutputStream(file);
            in = new ZDecodes(new FileInputStream(new File(zPath)));//需要解压的文件
            byte[] buf = new byte[8192];
            while (true) {
                int got = in.read(buf);
                if (got < 0)  break;
                outputStream.write(buf, 0, got);
            }
            outputStream.flush();
        } finally {
            if (null != outputStream) outputStream.close();
            if (null != in) in.close();
        }

        if(isNeedDelSrc){
            FileUtils.deleteFile(zPath);
        }
    }

    public static void main (String args[])  throws Exception
    {
       /* OutputStream outputStream = null;
        InputStream in = null;
        try {
            File tempFile = new File("D:/XXX.txt.Z");//需要解压的文件
            String filepath = "D:/222/XXX.txt";//解压后的存放路径
            outputStream = new FileOutputStream((new File(filepath)));
            in = new ZDecodes(new FileInputStream(tempFile));

            byte[] buf = new byte[100000];
            int tot = 0;
            long beg = System.currentTimeMillis();

            while (true)
            {
                int got = in.read(buf);
                if (got < 0)  break;
                // System.out.write(buf, 0, got);
                outputStream.write(buf, 0, got);
                tot += got;
            }
            outputStream.flush();
            long end = System.currentTimeMillis();
            System.err.println("Time: " + (end-beg)/1000. + " seconds");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != outputStream) outputStream.close();
            if (null != in) in.close();
        }
*/
       String zPath = "D:/XXX.txt.Z";//需要解压的文件
       String oPath = "D:/222/XXX.txt";//解压后的存放路径
        ZDecodes.ZDecodes(zPath, oPath);
    }
}

 

转载于:https://my.oschina.net/u/2376377/blog/827209

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值