Java压缩/解压缩文件或目录组件FileArchive(附可执行程序下载)

1. 测试程序最终截图
Java压缩/解压缩文件或目录组件FileArchive(附可执行程序下载)
2. 定义组件支持的算法
package org.file.util.archive;

/**
 * @author ALLEN
 * <br/>Define the compress algorithm
 * <br/>Support <b>{ Compress, UnCompress }</b>
 */
public enum Algorithm {

	Compress, /* Compress Algorithm */
	UnCompress /* UnCompress Algorithm */
	
}

3. 定义组件抽象父类
package org.file.util.archive;

import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

/**
 * @author ALLEN
 * <br/>Define the parent case collection of Compress and UnCompress
 */
public abstract class Archive {
	
	/**
	 * Define the default compress level { 9 }
	 */
	public static final int DEFAULT_COMPRESS_LEVEL = 9;
	
	/**
	 * Define the default buffer size { 2 << 19 = 1MB }
	 */
	protected static final int DEFAULT_BUFFER_SIZE = 2 << 19;
	
	/**
	 * Define the default file block { 100 }
	 */
	protected static final int DEFAULT_FILE_BLOCK = 100;

	/**
	 * Define the archive algorithm
	 */
	protected Algorithm algorithm;
	
	/**
	 * Define the ZIP file instance
	 */
	protected File zipFile;
	
	/**
	 * Define the meta files instance
	 */
	protected File[] metaFiles;
	
	/**
	 * Define the bytes which has finished reading
	 */
	protected long finished = 0L;
	
	/**
	 * Define the current total compressed size
	 */
	protected long compressSize = 0L;
	
	/**
	 * Define the total bytes of (sub)file(s)
	 */
	protected long total = 0L;
	
	/**
	 * Define the task startup time
	 */
	protected long start = System.currentTimeMillis();
	
	/**
	 * Define the task progress current time
	 */
	protected long current = this.start;
	
	/**
	 * Define the properties instance
	 */
	protected final Properties properties = new Properties();
	
	/**
	 * Define the progress listener linked list collection
	 */
	protected final List<ProgressListener> listeners = new LinkedList<ProgressListener>();
	
	/**
	 * The default constructor
	 * @param algorithm
	 * 				the archive algorithm
	 * @param zipFile
	 * 				the ZIP file instance
	 * @param metaFiles
	 * 				the meta files array
	 */
	protected Archive(Algorithm algorithm, File zipFile, File... metaFiles) {
		if (algorithm != null && zipFile != null) {
			this.algorithm = algorithm;
			this.zipFile = zipFile;
			this.metaFiles = metaFiles;
			this.properties.clear();
			this.listeners.clear();
			this.init();
		}
	}
	
	/**
	 * Initialize the compress or uncompress components
	 */
	protected abstract void init();
	
	/**
	 * The core compress and uncompress process
	 */
	protected abstract void process();
	
	/**
	 * Notify all registered progress listeners
	 */
	protected void notifyListeners() {
		for (ProgressListener listener : this.listeners)
			listener.progress(this.finished, this.compressSize, this.total, this.start, this.current, this.properties);
	}
	
	/**
	 * Register a new progress listener into the listeners linked list
	 * @param listener
	 * 			the ProgressListener instance
	 */
	public void registerProgressListener(ProgressListener listener) {
		if (listener != null)
			synchronized (this.listeners) {
				this.listeners.add(listener);
			}
	}
	
	/**
	 * Remove a progress listener from the listeners linked list
	 * @param listener
	 * 			the ProgressListener instance
	 */
	public void removeProgressListener(ProgressListener listener) {
		if (listener != null)
			synchronized (this.listeners) {
				this.listeners.remove(listener);
			}
	}
	
	/**
	 * Start the process task to execute
	 */
	public void execute() {
		synchronized (this) {
			this.process();
		}
	}

}

4. 压缩文件或目录实现
package org.file.util.archive;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * @author ALLEN
 * <br/>The child Compress implement from archive
 */
public class Compress extends Archive {
	
	/**
	 * Define the file collection vector
	 */
	private Map<String, File> hashMap;
	
	/**
	 * Define the compress level
	 */
	private int level = DEFAULT_COMPRESS_LEVEL;
	
	/**
	 * Define the compress comment
	 */
	private String comment = null;

	/**
	 * The default constructor
	 * @param algorithm
	 * 				the archive algorithm
	 * @param zipFile
	 * 				the ZIP file instance
	 * @param metaFiles
	 * 				the meta files array
	 */
	protected Compress(Algorithm algorithm, File zipFile, File... metaFiles) {
		super(algorithm, zipFile, metaFiles);
	}
	
	/**
	 * The recursive method which scans the file instance
	 */
	private void scan() {
		for (File file : this.metaFiles) {
			if (file.isFile()) {
				this.total += file.length();
				this.hashMap.put(file.getName(), file);
			}
			else if (file.isDirectory())
				this.make(file, file.getAbsolutePath().length() + 1);
		}
	}
	
	/**
	 * The recursive method which make new file record
	 * @param file
	 * 			the destination directory instance
	 * @param cutPos
	 * 			the parent directory cut position of current file
	 */
	private void make(File file, int cutPos) {
		for (File tmp : file.listFiles()) {
			if (tmp.isFile()) {
				this.total += tmp.length();
				this.hashMap.put(tmp.getAbsolutePath().substring(cutPos), tmp);
			} else if (tmp.isDirectory())
				this.make(tmp, cutPos);
		}
	}
	
	/**
	 * Set the compress level and comment
	 * @param level
	 * 			the compress level
	 * @param comment
	 * 			the compress comment
	 */
	public void setLevelAndComment(int level, String comment) {
		if (level > 0 && level < 10)
			this.level = level;
		this.comment = comment;
	}

	/* (non-Javadoc)
	 * @see org.file.util.archive.Archive#init()
	 */
	protected void init() {
		this.hashMap = new HashMap<String, File>();
		this.hashMap.clear();
		this.scan();
	}

	/* (non-Javadoc)
	 * @see org.file.util.archive.Archive#process()
	 */
	protected void process() {
		try {
			// update compressed size
			this.compressSize = this.total;
			// create output stream instance
			ZipOutputStream output = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(this.zipFile, false)));
			output.setLevel(this.level);
			output.setComment(this.comment);
			// define the input parameters
			BufferedInputStream input = null;
			long fileLength = 0L;
			int bufferSize = 0;
			int length = -1;
			byte[] buffer = null;
			// parser files
			Iterator<String> it = this.hashMap.keySet().iterator();
			if (it != null) {
				this.properties.setProperty("Count", String.valueOf(this.hashMap.size()));
				this.start = System.currentTimeMillis();
				while (it.hasNext()) {
					// get file information
					String relativePath = it.next();
					File file = this.hashMap.get(relativePath);
					// assign buffer size
					if ((fileLength = file.length()) < 0)
						continue;
					if (fileLength < DEFAULT_FILE_BLOCK)
						bufferSize = (int)fileLength;
					else if (Math.round((double)fileLength / DEFAULT_FILE_BLOCK) < DEFAULT_BUFFER_SIZE)
						bufferSize = DEFAULT_BUFFER_SIZE;
					else
						bufferSize = (int)Math.round((double)fileLength / DEFAULT_FILE_BLOCK);
					buffer = new byte[bufferSize];
					// create new file entry
					output.putNextEntry(new ZipEntry(relativePath));
					input = new BufferedInputStream(new FileInputStream(file), bufferSize);
					while ((length = input.read(buffer, 0, bufferSize)) != -1) {
						// update finished value
						this.finished += length;
						output.write(buffer, 0, length);
						// update current time value
						this.current = System.currentTimeMillis();
						// notify progress listeners
						this.notifyListeners();
					}
					input.close();
				}
			}
			output.flush();
			output.close();
			// update compressed size
			ZipFile zf = new ZipFile(this.zipFile.getAbsolutePath());
			this.compressSize = 0L;
			Iterator<String> _it = this.hashMap.keySet().iterator();
			while (_it.hasNext())
				this.compressSize += zf.getEntry(_it.next()).getCompressedSize();
			zf.close();
			this.notifyListeners();
		} catch (Exception e) {
			;
		}
	}

}

5. 解压缩文件实现
package org.file.util.archive;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * @author ALLEN
 * <br/>The child UnCompress implement from archive
 */
public class UnCompress extends Archive {
	
	/**
	 * Define the file entry collection
	 */
	private Vector<String> vector;

	/**
	 * The default constructor
	 * @param algorithm
	 * 				the archive algorithm
	 * @param zipFile
	 * 				the ZIP file instance
	 * @param metaFile
	 * 				the meta directory
	 */
	protected UnCompress(Algorithm algorithm, File zipFile, File metaFile) {
		super(algorithm, zipFile, metaFile);
	}
	
	/**
	 * Scan the ZIP compress file entries
	 */
	private void scan() {
		try {
			ZipFile zf = new ZipFile(this.zipFile.getAbsolutePath());
			Enumeration<?> en = zf.entries();
			if (en != null) {
				while (en.hasMoreElements())
					this.vector.add(((ZipEntry)en.nextElement()).getName());
			}
			zf.close();
			this.properties.setProperty("Count", String.valueOf(zf.size()));
		}  catch (Exception e) {
			;
		}
	}

	/* (non-Javadoc)
	 * @see org.file.util.archive.Archive#init()
	 */
	protected void init() {
		this.vector = new Vector<String>();
		this.vector.clear();
		this.scan();
	}

	/* (non-Javadoc)
	 * @see org.file.util.archive.Archive#process()
	 */
	protected void process() {
		File path = null;
		if (this.metaFiles.length != 1 || !(path = this.metaFiles[0]).isDirectory())
			return;
		try {
			// create ZIP file instance
			ZipFile zf = new ZipFile(this.zipFile);
			Iterator<String> _it = this.vector.iterator();
			while (_it.hasNext()) {
				ZipEntry entry = zf.getEntry(_it.next());
				this.compressSize += entry.getCompressedSize();
				this.total += entry.getSize();
			}
			// define uncompress parameters
			InputStream input = null;
			String absolutePath = null;
			File tmp = null;
			OutputStream output = null;
			long entryLength = 0L;
			int bufferSize = 0;
			int length = -1;
			byte[] buffer;
			// create iterator
			Iterator<String> it = this.vector.iterator();
			if (it != null) {
				this.start = System.currentTimeMillis();
				while (it.hasNext()) {
					// get file entry relative path
					String relativePath = it.next();
					ZipEntry entry = zf.getEntry(relativePath);
					// assign buffer size
					if ((entryLength = entry.getCompressedSize()) < 0)
						continue;
					if (entryLength < DEFAULT_FILE_BLOCK)
						bufferSize = (int)entryLength;
					else if (Math.round((double)entryLength / DEFAULT_FILE_BLOCK) < DEFAULT_BUFFER_SIZE)
						bufferSize = DEFAULT_BUFFER_SIZE;
					else
						bufferSize = (int)Math.round((double)entryLength / DEFAULT_FILE_BLOCK);
					buffer = new byte[bufferSize];
					// get input stream instance
					input = zf.getInputStream(entry);
					// create file is not exist
					absolutePath = path.getAbsolutePath() + System.getProperty("file.separator") + relativePath;
					tmp = new File(absolutePath.substring(0, absolutePath.lastIndexOf(System.getProperty("file.separator"))));
					tmp.mkdirs();
					tmp = new File(absolutePath);
					tmp.createNewFile();
					// uncompress data
					output = new BufferedOutputStream(new FileOutputStream(tmp, false), bufferSize);
					while ((length = input.read(buffer, 0, bufferSize)) != -1) {
						// update finished value
						this.finished += length;
						output.write(buffer, 0, length);
						// update current time value
						this.current = System.currentTimeMillis();
						// notify progress listeners
						this.notifyListeners();
					}
					output.flush();
					output.close();
					input.close();
				}
			}
			zf.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
}

6. 定义回掉函数,作为组件监听器
package org.file.util.archive;

import java.util.Properties;

/**
 * @author ALLEN
 * <br/>Define the archive progress listener
 */
public interface ProgressListener {

	/**
	 * Define the progress listener method which can read the archive progress
	 * @param finished
	 * 				the total bytes finished handling
	 * @param compressSize
	 * 				the current total compress size
	 * @param total
	 * 				the total bytes of data
	 * @param start
	 * 				the start time of progress
	 * @param current
	 * 				the current time of progress
	 * @param properties
	 * 				the result properties of archive
	 * 				<br/>properties key should be in <b>{ Count }<b/>
	 */
	public void progress(long finished, long compressSize, long total, long start, long current, Properties properties);
	
}

7. 组件核心控制器
package org.file.util.archive;

import java.io.File;

/**
 * @author ALLEN
 * <br/>Define the FileArchive which manages Compress and UnCompress
 */
public class FileArchive implements Runnable {

	/**
	 * Define the archive instance
	 */
	private Archive archive;
	
	/**
	 * The default constructor
	 * @param algorithm
	 * 				the archive algorithm
	 * @param zipFile
	 * 				the destination ZIP file
	 * @param metaFiles
	 * 				the meta files
	 */
	private FileArchive(Algorithm algorithm, File zipFile, File... metaFiles) {
		if (algorithm == Algorithm.Compress) {
			this.archive = new Compress(algorithm, zipFile, metaFiles);
		} else if (algorithm == Algorithm.UnCompress) {
			metaFiles[0].mkdirs();
			this.archive = new UnCompress(algorithm, zipFile, metaFiles[0]);
		}
	}
	
	/**
	 * Return an instance of FileArchive
	 * @param algorithm
	 * 				the archive algorithm
	 * @param absolutePath
	 * 				the destination ZIP file
	 * @param metaFiles
	 * 				the meta files
	 * @return
	 * 				a new instance of FileArchive
	 */
	public static FileArchive getInstance(Algorithm algorithm, String absolutePath, String... metaFiles) {
		return getInstance(algorithm, new File(absolutePath), metaFiles);
	}
	
	/**
	 * Return an instance of FileArchive
	 * @param algorithm
	 * 				the archive algorithm
	 * @param zipFile
	 * 				the destination ZIP file
	 * @param metaFiles
	 * 				the meta files
	 * @return
	 * 				a new instance of FileArchive
	 */
	public static FileArchive getInstance(Algorithm algorithm, File zipFile, String... metaFiles) {
		if (metaFiles != null) {
			int length = metaFiles.length;
			File[] files = new File[length];
			for (int i = 0; i < length; i++)
				files[i] = new File(metaFiles[i]);
			return getInstance(algorithm, zipFile, files);
		} else 
			return null;
	}
	
	/**
	 * Return an instance of FileArchive
	 * @param algorithm
	 * 				the archive algorithm
	 * @param absolutePath
	 * 				the destination ZIP file
	 * @param metaFiles
	 * 				the meta files
	 * @return
	 * 				a new instance of FileArchive
	 */
	public static FileArchive getInstance(Algorithm algorithm, String absolutePath, File... metaFiles) {
		return getInstance(algorithm, new File(absolutePath), metaFiles);
	}
	
	/**
	 * Return an instance of FileArchive
	 * @param algorithm
	 * 				the archive algorithm
	 * @param zipFile
	 * 				the destination ZIP file
	 * @param metaFiles
	 * 				the meta files
	 * @return
	 * 				a new instance of FileArchive
	 */
	public static FileArchive getInstance(Algorithm algorithm, File zipFile, File... metaFiles) {
		if (algorithm != null && zipFile != null && metaFiles != null)
			return new FileArchive(algorithm, zipFile, metaFiles);
		return null;
	}
	
	/**
	 * Register a new progress listener into the listeners linked list
	 * @param listener
	 * 			the ProgressListener instance
	 */
	public void registerProgressListener(ProgressListener listener) {
		if (this.archive != null)
			this.archive.registerProgressListener(listener);
	}
	
	/**
	 * Remove a progress listener from the listeners linked list
	 * @param listener
	 * 			the ProgressListener instance
	 */
	public void removeProgressListener(ProgressListener listener) {
		if (this.archive != null)
			this.archive.removeProgressListener(listener);
	}
	
	/**
	 * Start the archive task
	 */
	public synchronized void execute() {
		new Thread(this).start();
	}

	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		if (this.archive != null)
			this.archive.execute();
	}
	
}

8. 核心测试代码
package org.file.util.archive;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Properties;

import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * @author ALLEN
 * <br/>Archive test case
 */
public class ArchiveTest extends JFrame implements ProgressListener {
	
	private static final long serialVersionUID = -3707959572261992767L;
	
	private static String path = null;
	private static FileArchive fa;
	private static ArchiveTest self;
	
	private JLabel title;
	private JProgressBar progress;
	private JLabel label1;
	private JLabel label2;
	private JLabel label3;
	private static ButtonGroup group;
	private static JRadioButton button1;
	private static JRadioButton button2;
	private static JButton broswer;
	private static JButton un_compress;

	public ArchiveTest() {
		
		super("JAVA SDK FILEARCHIVE");
		self = this;
		this.setIconImage(new ImageIcon(this.getClass().getResource("/org/data/resource/images/title.png")).getImage());
		
		try {
			UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
		} catch (Exception e) {
			;
		}
		
		JPanel jPanel = new JPanel(null);
		jPanel.setOpaque(true);
		jPanel.setBackground(Color.ORANGE);
		jPanel.setPreferredSize(new Dimension(330, 170));
		
		this.title = new JLabel("*** JAVA SDK FILEARCHIVE 1.0.0.0 TESTCASE ***", JLabel.CENTER);
		this.title.setBounds(new Rectangle(10, 3, 310, 25));
		
		this.progress = new JProgressBar();
		this.progress.setStringPainted(true);
		this.progress.setValue(0);
		this.progress.setString("Waiting for selecting ......");
		this.progress.setBounds(new Rectangle(10, 25, 310, 25));
		
		this.label1 = new JLabel("[ Size ]    [ Time ]", JLabel.CENTER);
		this.label1.setBounds(new Rectangle(10, 50, 310, 25));
		
		this.label2 = new JLabel("[ Speed ]    [ Remain ]", JLabel.CENTER);
		this.label2.setBounds(new Rectangle(10, 70, 310, 25));
		
		this.label3 = new JLabel("[ Count ]    [ Compressed Ratio ]", JLabel.CENTER);
		this.label3.setBounds(new Rectangle(10, 90, 310, 25));
		
		group = new ButtonGroup();
		
		button1 = new JRadioButton("Compress");
		button1.setBounds(new Rectangle(60, 111, 100, 25));
		
		button2 = new JRadioButton("UnCompress");
		button2.setBounds(new Rectangle(180, 111, 100, 25));
		
		broswer = new JButton("Broswer");
		broswer.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser();
				chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
				int returnVal = chooser.showOpenDialog(null);
				if(returnVal == JFileChooser.APPROVE_OPTION) {
					path = chooser.getSelectedFile().getAbsolutePath();
				}
			}
		});
		broswer.setBounds(new Rectangle(10, 136, 150, 25));
		
		un_compress = new JButton("(Un) Compress");
		un_compress.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (path != null) {
					if (group.getSelection() == button1.getModel()) {
						fa = FileArchive.getInstance(Algorithm.Compress, new File("FILEARCHIVE.ZIP"), path);
						fa.registerProgressListener(self);
						broswer.setEnabled(false);
						un_compress.setEnabled(false);
						fa.execute();
					} else if (group.getSelection() == button2.getModel()) {
						fa = FileArchive.getInstance(Algorithm.UnCompress, new File("FILEARCHIVE.ZIP"), path);
						fa.registerProgressListener(self);
						broswer.setEnabled(false);
						un_compress.setEnabled(false);
						fa.execute();
					}
				}
			}
		});
		un_compress.setBounds(new Rectangle(168, 136, 150, 25));
		
		jPanel.add(this.title);
		jPanel.add(this.progress);
		jPanel.add(this.label1);
		jPanel.add(this.label2);
		jPanel.add(this.label3);
		group.add(button1);
		group.add(button2);
		group.setSelected(button1.getModel(), true);
		jPanel.add(button1);
		jPanel.add(button2);
		jPanel.add(broswer);
		jPanel.add(un_compress);
		
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setContentPane(jPanel);
		this.setSize(new Dimension(330, 170));
		this.setResizable(false);
		this.setVisible(true);
		Dimension resolution = Toolkit.getDefaultToolkit().getScreenSize();
		this.setLocation((int)resolution.getWidth() / 2 - 165, (int)resolution.getHeight() / 2 - 133);
		this.pack();
	}

	public void progress(long finished, long compressSize, long total, long start, long current, Properties properties) {
		float percent = (float) finished * 100 / total;
		long cost = current - start;
		double speed = (double)finished * 0.9765625 / cost;
		long remain = cost * (total - finished) / finished;
		this.progress.setValue((int)percent);
		this.progress.setString(String.format("%.2f%%", percent));
		this.label1.setText(String.format("[ Size: %d Bytes ]    [ Time: %d ms ]", total, cost));
		this.label2.setText(String.format("[ Speed: %.2f Bps ]    [ Remain: %d ms ]", speed, remain));
		this.label3.setText(String.format("[ Count: %s ]    [ Compressed Ratio: %.2f%% ]", properties.getProperty("Count"), (double)compressSize * 100 / total));
		if (finished == total) {
			broswer.setEnabled(true);
			un_compress.setEnabled(true);
		}
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {   
				com.sun.awt.AWTUtilities.setWindowOpacity(new ArchiveTest(), 1.00f);   
			}   
		}); 
	}

}

你可能感兴趣的:(java,thread,算法,swing,sun)