java:需要提高校验和计算的性能
我使用以下函数计算文件的校验和:java:需要提高校验和计算的性能,java,file-io,checksum,Java,File Io,Checksum,我使用以下函数计算文件的校验和: public static void generateChecksums(String strInputFile, String strCSVFile) { ArrayList<String[]> outputList = new ArrayList<String[]>(); try { MessageDigest m = MessageDigest.getInstance("MD5");
public static void generateChecksums(String strInputFile, String strCSVFile) {
ArrayList<String[]> outputList = new ArrayList<String[]>();
try {
MessageDigest m = MessageDigest.getInstance("MD5");
File aFile = new File(strInputFile);
InputStream is = new FileInputStream(aFile);
System.out.println(Calendar.getInstance().getTime().toString() +
" Processing Checksum: " + strInputFile);
double dLength = aFile.length();
try {
is = new DigestInputStream(is, m);
// read stream to EOF as normal...
int nTmp;
double dCount = 0;
String returned_content="";
while ((nTmp = is.read()) != -1) {
dCount++;
if (dCount % 600000000 == 0) {
System.out.println(". ");
} else if (dCount % 20000000 == 0) {
System.out.print(". ");
}
}
System.out.println();
} finally {
is.close();
}
byte[] digest = m.digest();
m.reset();
BigInteger bigInt = new BigInteger(1,digest);
String hashtext = bigInt.toString(16);
// Now we need to zero pad it if you actually / want the full 32 chars.
while(hashtext.length() < 32 ){
hashtext = "0" + hashtext;
}
String[] arrayTmp = new String[2];
arrayTmp[0] = aFile.getName();
arrayTmp[1] = hashtext;
outputList.add(arrayTmp);
System.out.println("Hash Code: " + hashtext);
UtilityFunctions.createCSV(outputList, strCSVFile, true);
} catch (NoSuchAlgorithmException nsae) {
System.out.println(nsae.getMessage());
} catch (FileNotFoundException fnfe) {
System.out.println(fnfe.getMessage());
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
}
从一个位置复制到另一个位置所需时间不到一分钟的3 GB文件,计算起来需要一个多小时。我可以做些什么来加速这个过程,还是应该尝试使用shell命令等不同的方向
更新:多亏ratchet freak的建议,我将代码改成了这个,速度快得离谱(我猜是2048X快了…):
使用缓冲区
byte[] buff = new byte[2048];
while ((nTmp = is.read(buff)) != -1)
{
dCount+=ntmp;
//this logic won't work anymore though
/*
if (dCount % 600000000 == 0)
{
System.out.println(". ");
}
else if (dCount % 20000000 == 0)
{
System.out.print(". ");
}
*/
}
编辑:或者,如果不需要这些值,请编辑
while(is.read(buff)!=-1)is.skip(600000000);
nvm显然是
DigestInputStream
的实现者很愚蠢,在发布之前没有正确地测试所有内容您尝试过删除println吗?我想所有的字符串操作可能会消耗大部分的处理
编辑:我没有读清楚,我现在意识到它们很少被输出,我会收回我的答案,但我想这并不是完全无价的:-p(对不起!)问题是System.out.print使用得太频繁了。每次调用它时,都必须创建新的字符串对象,而且代价很高 使用StringBuilder类或其线程安全模拟StringBuffer
StringBuilder sb = new StringBuilder();
每次需要添加内容时,请称之为:
sb.append("text to be added");
稍后,当您准备打印时:
system.out.println(sb.toString());
坦率地说,您的代码存在一些问题,导致其速度变慢:
read()
很可能在没有自动缓冲的情况下被转换为操作系统IOs调用,所以一个read()
就是一个系统调用!!!
如果使用数组作为缓冲区或BufferedInputStream
,操作系统通常会表现得更好。更好的是,您可以使用nio将文件映射到内存中,并尽可能快地读取它dCount++代码>计数器可能使用了很多周期。我相信即使是最新的Intel Core处理器,完成64位浮点加法也需要几个时钟周期。你最好在这个柜台上用一个长的。
如果此计数器的唯一用途是显示进度,则可以利用Java整数溢出而不会导致错误的事实,并在字符类型包装为0(即每65536次读取)时将进度显示提前
StringBuilder
或格式化程序
while(hashtext.length()<32){
hashtext=“0”+hashtext;
}其目的是指出标准化的进展。这是我模拟命令行ftp客户端的“散列”行为的方法。数据帐户%60000000执行打印项次与打印项次。打印项次只在一小部分时间出现。。。如果有任何影响性能的因素,则使用条件逻辑。+1:用于考虑控制台输出。在这种情况下,它不是唯一的性能增强,但许多程序员没有意识到在编写控制台时会有多少开销。它会显著降低应用程序的速度。被否决是因为“所有那些字符串操作”只会每两千万次迭代发生一次。
DigestInputStream
不会覆盖skip()
,因此跳过的字节将不会被Digest处理。显然,您没有阅读DigestInputStream的Javadoc,其中没有说skip会更新摘要。对愚蠢的评论投了反对票。伙计,它没有说任何关于skip的内容,他们也没有检查构造摘要上的nullpointer,这让你想清楚为什么在其他地方的包装流上会有一个NPE,因此skip()的行为是继承的,与所有三个read()方法的行为不同,记录这些信息以更新摘要。
sb.append("text to be added");
system.out.println(sb.toString());