Java计算文件校验和组件FileChecksum(附可运行程序下载)

1. 测试程序最终截图
[img]http://dl.iteye.com/upload/attachment/312522/bea32131-780c-3c12-8cd8-f7a1b7a5982c.png[/img]
2. 定义组件支持的算法
package org.file.util.checksum;

/**
* @author ALLEN
* <br/>Define the checksum calculation algorithm
* <br/>Support <b>{ Adler32, CRC32, MD2, MD5, SHA, SHA-1, SHA-256, SHA-384, SHA-512 }</b>
*/
public enum Algorithm {

Adler32, /* Adler32 Algorithm */
CRC32, /* CRC32 Algorithm */
MD2, /* MD2 Algorithm */
MD5, /* MD5 Algorithm */
SHA, /* SHA Algorithm */
SHA1, /* SHA-1 Algorithm */
SHA256, /* SHA-256 Algorithm */
SHA384, /* SHA-384 Algorithm */
SHA512 /* SHA-512 Algorithm */

}

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

import java.util.Properties;

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

/**
* Define the progress listener method which can read the calculation progress
* @param finished
* the total bytes finished reading
* @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 checksum
* <br/>properties key should be in <b>{ Name, Path, Size, LastModified, Hidden,
* Readable, Writable, Executable, Time, Adler32, CRC32, MD2, MD5, SHA,
* SHA-1, SHA-256, SHA-384, SHA-512 }<b/>
*/
public void progress(long finished, long total, long start, long current, Properties properties);

}

4. 核心算法实现
package org.file.util.checksum;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.Adler32;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

/**
* @author ALLEN
* <br/>Calculate the checksum of the specified file
*/
public class FileChecksum implements Runnable {

/**
* Define hex digit value <b>{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F }</b>
*/
private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

/**
* Define the default buffer size { 2 << 19 = 1MB }
*/
private static final int DEFAULT_BUFFER_SIZE = 2 << 19;

/**
* Define the default file block { 500 }
*/
private static final int DEFAULT_FILE_BLOCK = 500;

/**
* Define the default date format pattern
*/
private static final String PATTERN = "ZZ F yyyy-MM-dd HH:mm:ss:SSS";

/**
* Define the { f: Algorithm -> String } hash map table
*/
private static final Map<Algorithm, String> hashMap = new HashMap<Algorithm, String>();

/**
* Initialize the { f: Algorithm -> String } hash map table
*/
static {
hashMap.clear();
hashMap.put(Algorithm.Adler32, "java.util.zip.Adler32");
hashMap.put(Algorithm.CRC32, "java.util.zip.CRC32");
hashMap.put(Algorithm.MD2, "MD2");
hashMap.put(Algorithm.MD5, "MD5");
hashMap.put(Algorithm.SHA, "SHA");
hashMap.put(Algorithm.SHA1, "SHA-1");
hashMap.put(Algorithm.SHA256, "SHA-256");
hashMap.put(Algorithm.SHA384, "SHA-384");
hashMap.put(Algorithm.SHA512, "SHA-512");
}

/**
* Define the file instance
*/
private File file;

/**
* Define the checksum algorithm collection
*/
private Algorithm[] algorithms;

/**
* Define the default date format pattern instance
*/
private final SimpleDateFormat sdf = new SimpleDateFormat(PATTERN);

/**
* Define the checksum calculation collection
*/
private final List<Checksum> checksums = new LinkedList<Checksum>();
private final List<MessageDigest> messageDigests = new LinkedList<MessageDigest>();

/**
* Define the configuration parameters
*/
private final Object[] config = {false, null, null};

/**
* Define the result properties collection
*/
private final Properties properties = new Properties();

/**
* Define the progress listener linked list collection
*/
private final List<ProgressListener> listeners = new LinkedList<ProgressListener>();

/**
* The default constructor
* @param file
* the file instance
* @param algorithms
* the checksum algorithm collection
*/
private FileChecksum(File file, Algorithm... algorithms) {
this.file = file;
this.algorithms = algorithms;
this.init();
}

/**
* Return an instance of FileChecksum type
* @param absolutePath
* the absolute path of the specified file
* @param algorithms
* the checksum algorithm collection
* @return
* an instance of FileChecksum type
*/
public static FileChecksum getInstance(String absolutePath, Algorithm... algorithms) {
String separator = System.getProperty("file.separator");
int lastPos = absolutePath.lastIndexOf(separator);
String path = absolutePath.substring(0, lastPos);
String name = absolutePath.substring(lastPos + 1, absolutePath.length());
return getInstance(path, name, algorithms);
}

/**
* Return an instance of FileChecksum type
* @param path
* the path of the specified file
* @param name
* the name of the specified file
* @param algorithms
* the checksum algorithm collection
* @return
* an instance of FileChecksum type
*/
public static FileChecksum getInstance(String path, String name, Algorithm... algorithms) {
return getInstance(new File(path, name), algorithms);
}

/**
* Return an instance of FileChecksum type
* @param file
* the file instance of the specified file
* @param algorithms
* the checksum algorithm collection
* @return
* an instance of FileChecksum type
*/
public static FileChecksum getInstance(File file, Algorithm... algorithms) {
return new FileChecksum(file, algorithms);
}

/**
* Convert bytes array to string
* @param bytes
* the bytes array
* @return
* the string of bytes array
*/
private static String bytesToString(byte[] bytes) {
StringBuffer result = new StringBuffer(2 * bytes.length);
for (int i = 0; i < bytes.length; i++)
result.append(hexDigits[(bytes[i] & 0xF0) >> 4]).append(hexDigits[bytes[i] & 0x0F]);
return result.toString().toUpperCase();
}

/**
* Convert long to string
* @param checksum
* the long value
* @return
* the string of long
*/
private static String longToString(long checksum) {
return Long.toHexString(checksum).toUpperCase();
}

/**
* Initialize the calculation component
*/
private void init() {
// clear
this.checksums.clear();
this.messageDigests.clear();
this.listeners.clear();
// parser the algorithms
try {
for (int i = 0; i < this.algorithms.length; i++) {
String algorithm = hashMap.get(this.algorithms[i]);
if (this.algorithms[i] == null)
continue;
else if (this.algorithms[i] == Algorithm.Adler32)
this.checksums.add((Adler32)Class.forName(algorithm).newInstance());
else if (this.algorithms[i] == Algorithm.CRC32)
this.checksums.add((CRC32)Class.forName(algorithm).newInstance());
else
this.messageDigests.add(MessageDigest.getInstance(algorithm));
}
} catch (Exception e) {
;
}
}

/**
* Calculate the checksum of the specified file
*/
private void process() {
// assign buffer size
final long fileLength = this.file.length();
int bufferSize = -1;
if (fileLength < 0L)
return;
else 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);
// set file properties
this.properties.setProperty("Name", this.file.getName());
this.properties.setProperty("Path", this.file.getAbsolutePath());
this.properties.setProperty("Size", String.valueOf(fileLength));
this.properties.setProperty("LastModified", this.sdf.format(new Date(this.file.lastModified())));
this.properties.setProperty("Hidden", String.valueOf(this.file.isHidden()));
this.properties.setProperty("Readable", String.valueOf(this.file.canRead()));
this.properties.setProperty("Writable", String.valueOf(this.file.canWrite()));
this.properties.setProperty("Executable", String.valueOf(this.file.canExecute()));
// calculate file checksum
try {
BufferedInputStream input = new BufferedInputStream(new FileInputStream(this.file), bufferSize);
byte[] buffer = new byte[bufferSize];
int length = -1;
long finished = 0L;
long start, current;
start = current = System.currentTimeMillis();
while ((finished < fileLength) && (length = input.read(buffer, 0, bufferSize)) != -1) {
finished += length;
// update checksums
for (int i = 0; i < this.checksums.size(); i++) {
Checksum checksum = this.checksums.get(i);
checksum.update(buffer, 0, length);
if (checksum instanceof Adler32)
this.properties.setProperty("Adler32", longToString(checksum.getValue()));
else if (checksum instanceof CRC32)
this.properties.setProperty("CRC32", longToString(checksum.getValue()));
else
continue;
}
// update message digests
for (int i = 0; i < this.messageDigests.size(); i++) {
MessageDigest messageDigest = this.messageDigests.get(i);
messageDigest.update(buffer, 0, length);
this.properties.setProperty(messageDigest.getAlgorithm(), bytesToString(((MessageDigest)messageDigest.clone()).digest()));
}
// update current calculation time
current = System.currentTimeMillis();
// notify progress listeners
synchronized (this.listeners) {
for (ProgressListener listener : this.listeners)
listener.progress(finished, fileLength, start, current, this.properties);
}
}
this.properties.setProperty("Time", String.valueOf(current - start));
input.close();
} catch (Exception e) {
;
}
}

/**
* 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);
}
}

/**
* Set the properties XML file parameters
*/
public void setDefaultXMLConfig() {
synchronized (this.config) {
this.config[0] = true;
this.config[1] = "CHECKSUM_" + longToString(System.nanoTime()) + ".XML";
this.config[2] = null;
}
}

/**
* Set the properties XML file parameters
* @param comment
* the comment of XML file
*/
public void setDefaultXMLConfig(String comment) {
synchronized (this.config) {
this.config[0] = true;
this.config[1] = "CHECKSUM_" + longToString(System.nanoTime()) + ".XML";
this.config[2] = comment;
}
}

/**
* Set the properties XML file parameters
* @param absolutePath
* the absolute path of the destination file
* @param comment
* the comment of XML file
*/
public void setDefaultXMLConfig(String absolutePath, String comment) {
synchronized (this.config) {
this.config[0] = true;
this.config[1] = absolutePath;
this.config[2] = comment;
}
}

/**
* Start the process thread to run
*/
public synchronized void execute() {
new Thread(this).start();
}

/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
public void run() {
synchronized (this) {
this.process();
try {
if ((Boolean)this.config[0])
this.properties.storeToXML(new FileOutputStream((String)this.config[1], false), (String)this.config[2], "UTF-8");
} catch (Exception e) {
;
}
}
}

}

5. 核心测试代码
package org.file.util.checksum;

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.util.Properties;

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.SwingUtilities;
import javax.swing.UIManager;

/**
* @author ALLEN
* <br/>Checksum test case
*/
public class ChecksumTest extends JFrame implements ProgressListener {

private static final long serialVersionUID = -3707959572261992767L;

private static String path = null;
private static FileChecksum fc;
private static ChecksumTest self;

private JLabel title;
private JProgressBar progress;
private JLabel label1;
private JLabel label2;
private JLabel label3;
private JLabel label4;
private JLabel label5;
private JLabel label6;
private JLabel label7;
private JLabel label8;
private JLabel label9;
private static JButton broswer;
private static JButton calculate;

public ChecksumTest() {

super("JAVA SDK FILECHECKSUM");
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, 267));

this.title = new JLabel("*** JAVA SDK FILECHECKSUM 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("[ Name ]", JLabel.CENTER);
this.label1.setBounds(new Rectangle(10, 50, 310, 25));

this.label2 = new JLabel("[ Modified ]", JLabel.CENTER);
this.label2.setBounds(new Rectangle(10, 70, 310, 25));

this.label3 = new JLabel("[ Readable ] [ Writable ]", JLabel.CENTER);
this.label3.setBounds(new Rectangle(10, 90, 310, 25));

this.label4 = new JLabel("[ Executable ] [ Hidden ]", JLabel.CENTER);
this.label4.setBounds(new Rectangle(10, 110, 310, 25));

this.label5 = new JLabel("[ Size ] [ Time ]", JLabel.CENTER);
this.label5.setBounds(new Rectangle(10, 130, 310, 25));

this.label6 = new JLabel("[ Speed ] [ Remain ]", JLabel.CENTER);
this.label6.setBounds(new Rectangle(10, 150, 310, 25));

this.label7 = new JLabel("[ Adler32 ] [ CRC32 ]", JLabel.CENTER);
this.label7.setBounds(new Rectangle(10, 170, 310, 25));

this.label8 = new JLabel("[ MD5 ]", JLabel.CENTER);
this.label8.setBounds(new Rectangle(10, 190, 310, 25));

this.label9 = new JLabel("[ SHA-1 ]", JLabel.CENTER);
this.label9.setBounds(new Rectangle(5, 210, 320, 25));

broswer = new JButton("Broswer");
broswer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int returnVal = chooser.showOpenDialog(null);
if(returnVal == JFileChooser.APPROVE_OPTION) {
path = chooser.getSelectedFile().getAbsolutePath();
}
}
});
broswer.setBounds(new Rectangle(10, 233, 150, 25));

calculate = new JButton("Calculate");
calculate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (path != null) {
fc = FileChecksum.getInstance(path, Algorithm.Adler32, Algorithm.CRC32, Algorithm.MD5, Algorithm.SHA1);
fc.registerProgressListener(self);
fc.setDefaultXMLConfig("GENERATED BY JAVA SDK FILECHECKSUM 1.0.0.0");
broswer.setEnabled(false);
calculate.setEnabled(false);
fc.execute();
}
}
});
calculate.setBounds(new Rectangle(168, 233, 150, 25));

jPanel.add(this.title);
jPanel.add(this.progress);
jPanel.add(this.label1);
jPanel.add(this.label2);
jPanel.add(this.label3);
jPanel.add(this.label4);
jPanel.add(this.label5);
jPanel.add(this.label6);
jPanel.add(this.label7);
jPanel.add(this.label8);
jPanel.add(this.label9);
jPanel.add(broswer);
jPanel.add(calculate);

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(jPanel);
this.setSize(new Dimension(330, 267));
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 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("[ Name: %s ]", properties.getProperty("Name")));
this.label2.setText(String.format("[ Modified: %s ]", properties.getProperty("LastModified")));
this.label3.setText(String.format("[ Readable: %s ] [ Writable: %s ]", properties.getProperty("Readable"), properties.getProperty("Writable")));
this.label4.setText(String.format("[ Executable: %s ] [ Hidden: %s ]", properties.getProperty("Readable"), properties.getProperty("Hidden")));
this.label5.setText(String.format("[ Size: %d Bytes ] [ Time: %d ms ]", total, cost));
this.label6.setText(String.format("[ Speed: %.2f Bps ] [ Remain: %d ms ]", speed, remain));
this.label7.setText(String.format("[ Adler32: %s ] [ CRC32: %s ]", properties.getProperty("Adler32"), properties.getProperty("CRC32")));
this.label8.setText(String.format("[ MD5: %s ]", properties.getProperty("MD5")));
this.label9.setText(String.format("[ %s ]", properties.getProperty("SHA-1")));
if (finished == total) {
broswer.setEnabled(true);
calculate.setEnabled(true);
}
}

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

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值