首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java:需要提高校验和计算的性能

java:需要提高校验和计算的性能
EN

Stack Overflow用户
提问于 2011-05-23 07:34:46
回答 3查看 1.9K关注 0票数 7

我使用以下函数来计算文件的校验和:

代码语言:javascript
复制
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());
    }
}

问题是读入文件的循环非常慢:

代码语言:javascript
复制
while ((nTmp = is.read()) != -1) {
    dCount++;
    if (dCount % 600000000 == 0) {
        System.out.println(". ");
    } else if (dCount % 20000000 == 0) {
        System.out.print(". ");
    }
}

一个3 GB的文件从一个位置复制到另一个位置只需不到一分钟,但计算起来却需要一个多小时。我是否可以做些什么来加快速度,或者我应该尝试不同的方向,比如使用shell命令?

更新:多亏了ratchet freak的建议,我把代码改成这样,速度快得离谱(我猜快2048倍...):

代码语言:javascript
复制
byte[] buff = new byte[2048];
while ((nTmp = is.read(buff)) != -1) {
    dCount += 2048;
    if (dCount % 614400000 == 0) {
        System.out.println(". ");
    } else if (dCount % 20480000 == 0) {
        System.out.print(". ");
    }
}
EN

回答 3

Stack Overflow用户

发布于 2011-05-23 07:41:33

你试过移除println吗?我想所有的字符串操作都会消耗大部分的处理时间!

编辑:我没有看清楚,我现在意识到它们很少被输出,我会收回我的答案,但我猜它并不是完全无价的:-p (对不起!)

票数 2
EN

Stack Overflow用户

发布于 2011-05-23 07:53:55

问题是System.out.print使用得太频繁了。每次调用它时,都必须创建新的String对象,而且开销很大。

请改用StringBuilder类或它的线程安全模拟StringBuffer。

代码语言:javascript
复制
StringBuilder sb = new StringBuilder();

每次你需要添加一些东西的时候,调用这个:

代码语言:javascript
复制
sb.append("text to be added");

稍后,当您准备打印它时:

代码语言:javascript
复制
system.out.println(sb.toString());
票数 0
EN

Stack Overflow用户

发布于 2011-05-23 08:02:02

坦率地说,你的代码中有几个问题使它变得很慢:

  1. 就像ratchet freak所说的,磁盘读取必须被缓冲,因为Java read()可能被转换为操作系统IOs调用而没有自动缓冲,所以一个read()就是一个系统调用!如果您使用数组作为缓冲区或BufferedInputStream,操作系统通常会执行得更好。更好的是,你可以使用nio将文件映射到内存中,并以操作系统可以处理的速度读取它。
  2. 你可能不相信,但dCount++;计数器可能已经使用了很多周期。我相信即使是最新的英特尔酷睿处理器,也需要几个时钟周期才能完成64位浮点加法。对于这个计数器,你最好使用一个长整型。如果此计数器的唯一目的是显示进度,则可以利用Java整数溢出而不会导致错误的事实,并在char类型换行为0(即每65536次读取)时提前显示进度。
  3. 以下字符串填充也是低效的。您应该使用StringBuilderFormatter

while(hashtext.length() < 32 ){ hashtext = "0"+hashtext;}

  • 尝试使用探查器查找代码

中的更多效率问题

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6091544

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档