java代码实现加密压缩文件解压

本文介绍了一个用于解密受密码保护的ZIP文件的Java类ZipDecryptInputStream。该类通过读取和处理ZIP文件头来实现解密功能,并演示了如何使用此类从受密码保护的ZIP文件中读取内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.dashu.basicinfo.zip;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZipDecryptInputStream extends InputStream {
   private static final int[] CRC_TABLE = new int[256];
   // compute the table
   // (could also have it pre-computed - see http://snippets.dzone.com/tag/crc32)
   static {
       for (int i = 0; i < 256; i++) {
           int r = i;
           for (int j = 0; j < 8; j++) {
               if ((r & 1) == 1) {
                   r = (r >>> 1) ^ 0xedb88320;
               } else {
                   r >>>= 1;
               }
           }
           CRC_TABLE[i] = r;
       }
   }

   private static final int DECRYPT_HEADER_SIZE = 12;
   private static final int[] LFH_SIGNATURE = {0x50, 0x4b, 0x03, 0x04};

   private final InputStream delegate;
   private final String password;
   private final int keys[] = new int[3];

   private State state = State.SIGNATURE;
   private int skipBytes;
   private int compressedSize;
   private int value;
   private int valuePos;
   private int valueInc;

   public ZipDecryptInputStream(InputStream stream, String password) {
       this.delegate = stream;
       this.password = password;
   }

   @Override
   public int read() throws IOException {
       int result = delegate.read();
       if (skipBytes == 0) {
           switch (state) {
               case SIGNATURE:
                   if (result != LFH_SIGNATURE[valuePos]) {
                       state = State.TAIL;
                   } else {
                       valuePos++;
                       if (valuePos >= LFH_SIGNATURE.length) {
                           skipBytes = 2;
                           state = State.FLAGS;
                       }
                   }
                   break;
               case FLAGS:
                   if ((result & 1) == 0) {
                       throw new IllegalStateException("ZIP not password protected.");
                   }
                   if ((result & 64) == 64) {
                       throw new IllegalStateException("Strong encryption used.");
                   }
                   if ((result & 8) == 8) {
                       throw new IllegalStateException("Unsupported ZIP format.");
                   }
                   result -= 1;
                   compressedSize = 0;
                   valuePos = 0;
                   valueInc = DECRYPT_HEADER_SIZE;
                   state = State.COMPRESSED_SIZE;
                   skipBytes = 11;
                   break;
               case COMPRESSED_SIZE:
                   compressedSize += result << (8 * valuePos);
                   result -= valueInc;
                   if (result < 0) {
                       valueInc = 1;
                       result += 256;
                   } else {
                       valueInc = 0;
                   }
                   valuePos++;
                   if (valuePos > 3) {
                       valuePos = 0;
                       value = 0;
                       state = State.FN_LENGTH;
                       skipBytes = 4;
                   }
                   break;
               case FN_LENGTH:
               case EF_LENGTH:
                   value += result << 8 * valuePos;
                   if (valuePos == 1) {
                       valuePos = 0;
                       if (state == State.FN_LENGTH) {
                           state = State.EF_LENGTH;
                       } else {
                           state = State.HEADER;
                           skipBytes = value;
                       }
                   } else {
                       valuePos = 1;
                   }
                   break;
               case HEADER:
                   initKeys(password);
                   for (int i = 0; i < DECRYPT_HEADER_SIZE; i++) {
                       updateKeys((byte) (result ^ decryptByte()));
                       result = delegate.read();
                   }
                   compressedSize -= DECRYPT_HEADER_SIZE;
                   state = State.DATA;
                   // intentionally no break
               case DATA:
                   result = (result ^ decryptByte()) & 0xff;
                   updateKeys((byte) result);
                   compressedSize--;
                   if (compressedSize == 0) {
                       valuePos = 0;
                       state = State.SIGNATURE;
                   }
                   break;
               case TAIL:
                   // do nothing
           }
       } else {
           skipBytes--;
       }
       return result;
   }

   @Override
   public void close() throws IOException {
       delegate.close();
       super.close();
   }

   private void initKeys(String password) {
       keys[0] = 305419896;
       keys[1] = 591751049;
       keys[2] = 878082192;
       for (int i = 0; i < password.length(); i++) {
           updateKeys((byte) (password.charAt(i) & 0xff));
       }
   }

   private void updateKeys(byte charAt) {
       keys[0] = crc32(keys[0], charAt);
       keys[1] += keys[0] & 0xff;
       keys[1] = keys[1] * 134775813 + 1;
       keys[2] = crc32(keys[2], (byte) (keys[1] >> 24));
   }

   private byte decryptByte() {
       int temp = keys[2] | 2;
       return (byte) ((temp * (temp ^ 1)) >>> 8);
   }

   private int crc32(int oldCrc, byte charAt) {
       return ((oldCrc >>> 8) ^ CRC_TABLE[(oldCrc ^ charAt) & 0xff]);
   }

   private static enum State {
       SIGNATURE, FLAGS, COMPRESSED_SIZE, FN_LENGTH, EF_LENGTH, HEADER, DATA, TAIL
   }
   
   
	public static void main(String[] args) throws Exception {
		  // password-protected zip file I need to read
      FileInputStream fis = new FileInputStream("d:/123/one.zip");
      // wrap it in the decrypt stream
      ZipDecryptInputStream zdis = new ZipDecryptInputStream(fis, "1234567");
      // wrap the decrypt stream by the ZIP input stream
      ZipInputStream zis = new ZipInputStream(zdis);

      // read all the zip entries and save them as files
      ZipEntry ze;
      while ((ze = zis.getNextEntry()) != null) {
      	File f = new File("d:/123/"+ze.getName());
          FileOutputStream fos = new FileOutputStream(f);
          int b;
          try {
				while ((b = zis.read()) != -1) {
				    fos.write(b);
				}
			} catch (Exception e) {
				fos.close();
				f.delete();
				 zis.closeEntry();
				 break;
			}
          fos.close();
          zis.closeEntry();
      }
      zis.close();
	}
}


有时候编码有问题 要根据具体情况处理

  1. ZipInputStream zis = new ZipInputStream(zdis,Charset.forName("GBK"));



压缩文件方法 该方法需要引用zip4j的jar文件 单个文件、多个文件压缩 /** * 使用给定密码压缩指定文件文件夹到指定位置. * * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"". * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀; * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名. * @param src 要压缩的文件文件夹路径 * @param dest 压缩文件存放路径 * @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效. * 如果为false,将直接压缩目录下文件压缩文件. * @param passwd 压缩使用的密码 * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. */ 方法详细见文件! 可选择文件list压缩 /** * 使用给定密码压缩指定文件list * dest可传最终压缩文件存放的绝对路径,也可以传存放目录,也可以传null或者"". * 如果传null或者""则将压缩文件存放在当前目录,即跟源文件同目录,压缩文件名取源文件名,以.zip为后缀; * 如果以路径分隔符(File.separator)结尾,则视为目录,压缩文件名取源文件名,以.zip为后缀,否则视为文件名. * @param src 要压缩的文件集合 * @param dest 压缩文件存放路径 * @param isCreateDir 是否在压缩文件里创建目录,仅在压缩文件为目录时有效. * 如果为false,将直接压缩目录下文件压缩文件. * @param passwd 压缩使用的密码 * @return 最终的压缩文件存放的绝对路径,如果为null则说明压缩失败. */ 方法详细见文件解压 /** * 使用给定密码解压指定的ZIP压缩文件到指定目录 * * 如果指定目录不存在,可以自动创建,不合法的路径将导致异常被抛出 * @param zipFile 指定的ZIP压缩文件 * @param dest 解压目录 * @param passwd ZIP文件的密码 * @return 解压文件数组 * @throws ZipException 压缩文件有损坏或者解压缩失败抛出 */ 方法详细见文件! 一个简单的demo 欢迎大家指点,一起提升
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值