【问题标题】:Java program slow down by printing lineJava程序通过打印线减慢
【发布时间】:2014-03-08 12:27:28
【问题描述】:

您好,我有一个脚本,下载是来自网络的文件,这样做会打印出进度。问题是打印出进度的行会大大降低程序的速度,有什么办法可以阻止它吗?

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;


public class download {
public static void main(String[] args) {
    try{
        URL u = new URL("http://upload.wikimedia.org/wikipedia/commons/1/16/Appearance_of_sky_for_weather_forecast,_Dhaka,_Bangladesh.JPG");
        FileOutputStream fos = new FileOutputStream("C://Users/xxx/Desktop/test.jpg");
        InputStream is = u.openStream();

        long size = u.openConnection().getContentLengthLong();
        int data;
        long done = 0;
        while((data = is.read())!=-1){
            double progress = (double) (done)/(double)(size)*100;
            System.out.println(progress); // if we dont do this then then it completes fast
            fos.write(data);
            done++;
        }
        fos.close();
    }catch(Exception e){
       e.printStackTrace();
    }
}
}

【问题讨论】:

    标签: java inputstream


    【解决方案1】:

    首先,每个 I/O 操作都需要很高的成本。现在,为每个读取的字节打印一条消息!(在InputStream#read 中注明)。

    如果您想要/需要打印进度,请读取一堆 KB,通常每 4 KB。您可以通过使用byte[] buffer 从流中读取和写入数据来做到这一点。

    BufferedInputStream input = null;
    BufferedOutStream output = null;
    final int DEFAULT_BUFFER_SIZE = 4 * 1024;
    try {
        input = new BufferedInputStream(is, DEFAULT_BUFFER_SIZE);
        output = new BufferedOutputStream(fos, DEFAULT_BUFFER_SIZE);
    
        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        int length;
        while ((length = input.read(buffer)) > 0) {
            output.write(buffer, 0, length);
            done += length;
            double progress = (double) (done)/(double)(size)*100
            System.out.println(progress);
        }
    } catch (IOException e) {
        //log your exceptions...
    } finally {
        closeResource(output);
        closeResource(input);
    }
    

    还有这个closeResource 方法:

    public void closeResource(Closeable resource) {
        if (resource != null) {
            try {
                resource.close();
            } catch (IOException e) {
                logger.error("Error while closing the resource.", e);
            }
        }
    }
    

    【讨论】:

    • 最好至少关闭output,以防万一或不能保证文件完整。
    • @zapl 我的代码不完整且具有误导性。更新了答案。
    • @user550 我相信这是正确的答案。我的回答解决了你的症状,但这个解决了你的问题。
    • 还有一个小问题,如果你在写作时忽略了关闭错误,你可能会错过在那段时间发生的最终刷新期间发生的错误 :) (我通常在 try 中为编写者额外关闭阻止,因此错误会与其他异常一起处理)
    【解决方案2】:

    尝试只打印每个第 x 个循环。

    if(done % 10 == 0) System.out.println(progress);
    

    【讨论】:

    • 这是唯一的方法吗?我认为我可以使用线程来解决问题?
    • 我敢肯定还有其他人,但是在控制台应用程序中显示进度的线程可能是矫枉过正
    • K.I.S.S 直到它需要小于 S
    • @user550 使用线程不会解决任何问题,因为它们会写入同一个磁盘。
    • @LuiggiMendoza 我不同意。这很简单,但效率低下。尽管我的回答直接回答了问题,但我相信您的回答是正确的解决方案。
    【解决方案3】:

    建议:不要在循环的每次迭代中打印进度。使用一个计数器,确定一个合理的频率,一个修改计数器的数字,并以该选定的频率打印进度。

    【讨论】:

      【解决方案4】:

      只有在(done % 100 == 0) 假设时才能打印该行。

      另外,您可以使用缓冲读取方式,这样可以加快程序速度。

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-09
      • 2021-11-24
      • 1970-01-01
      • 1970-01-01
      • 2013-12-19
      相关资源
      最近更新 更多