【问题标题】:File Downloader with Java Commons IO stuck at 1MB/s+带有 Java Commons IO 的文件下载器卡在 1MB/s+
【发布时间】:2023-01-03 00:33:08
【问题描述】:

最近我一直在尝试使用 Java 和 Commons IO 尝试创建一个网络文件下载器,但是我遇到了一个问题,事实上,当从浏览器运行相同的下载时,文件下载速度似乎不超过 1MB/s以 3MB /s 的速度流畅运行。你可以帮帮我吗?我将不胜感激。

这是我的下载器代码:

package com.application.steammachine;

import com.github.junrar.Archive;
import com.github.junrar.Junrar;
import com.github.junrar.exception.RarException;
import com.github.junrar.rarfile.FileHeader;
import com.github.junrar.volume.FileVolumeManager;
import javafx.beans.property.SimpleStringProperty;
import javafx.concurrent.Task;
import org.apache.commons.io.IOUtils;
import org.ini4j.Wini;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;

public class Downloader extends Task<Void> {

    private URL url;
    private String fileName;
    private Game game;

    public Downloader(URL url, String fileName, Game game) {
        this.url = url;
        this.fileName = fileName;
        this.game = game;
    }

    public class ProgressListener implements ActionListener {

        private double bytes = 0;
        private double mbDownloaded = 0;
        private double fileSize = 0;
        private double lastMB = 0;
        private long initialTime;
        private double speed = 0;
        private String downloadedText = "";
        private String sizeText;

        public ProgressListener(double fileSize){
            this.fileSize = fileSize;
            initialTime = System.nanoTime();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            bytes = ((DownloadCountingOutputStream) e.getSource()).getByteCount();
            updateProgress(bytes, fileSize);
            mbDownloaded = round(bytes/1e+6, 2);

            if(fileSize >= 1073741824){ //>= 1GB
                double temp = ((fileSize/1e+6)/1024);
                sizeText = round(temp,2) + " GB";
            }else {
                double temp = (fileSize/1e+6);
                sizeText = round(temp,2) + " MB";
            }

            if(mbDownloaded >= 1024){
                downloadedText = String.valueOf(round(mbDownloaded/1024,2));
            }else{
                downloadedText = String.valueOf(mbDownloaded);
            }

            if((System.nanoTime() - initialTime) >= (Math.pow(10, 9))){
                speed = round((mbDownloaded - lastMB), 3);
                initialTime = System.nanoTime();
                lastMB = mbDownloaded;
            }

            updateMessage(String.valueOf(speed)+"MB/s,"+String.valueOf(downloadedText + "/" + sizeText));
        }
    }

    @Override
    protected Void call() throws Exception {

        URL dl = this.url;
        File fl = null;
        String x = null;
        OutputStream os = null;
        InputStream is = null;

        try {

            updateMessage("Searching files...,---/---");

            fl = new File(Settings.getInstallPath() +"/"+ this.fileName);
            os = new FileOutputStream(fl);
            is = dl.openStream();

            DownloadCountingOutputStream dcount = new DownloadCountingOutputStream(os);

            double fileSize = Double.valueOf(dl.openConnection().getHeaderField("Content-Length"));

            ProgressListener progressListener = new ProgressListener(fileSize);
            dcount.setListener(progressListener);

            IOUtils.copy(is, dcount, 8192 );

            updateMessage("Concluding...,Almost finished");

        } catch (Exception e) {

            System.out.println(e);
            IOUtils.closeQuietly(os);
            IOUtils.closeQuietly(is);
            updateMessage(",");
            this.cancel(true);
            return null;

        } finally {

            IOUtils.closeQuietly(os);
            IOUtils.closeQuietly(is);


            updateMessage(",");
            updateProgress(0, 0);
            this.cancel(true);
            return null;

        }
    }


    protected static double round(double value, int places) {
        if (places < 0) throw new IllegalArgumentException();

        BigDecimal bd = new BigDecimal(Double.toString(value));
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    }

}

提前致谢

【问题讨论】:

    标签: java apache-commons-io


    【解决方案1】:

    首先,您可以尝试一些简单的事情来加快传输速度:

    1. 尝试使用更大的传输缓冲区大小。将 8K 缓冲区大小更改为 64K 或 512K。

    2. 去掉DownloadCountingOutputStream,直接转到FileOutputStream

      这些应该很容易尝试......而且他们可能帮助一下。


      在 Linux 系统上,用使用内核零拷贝传输支持的代码替换 Apache IOUtils.copy 调用可能也是值得的。有关解释,请参阅Efficient data transfer through zero copy

      文章中的示例是使用transferTo上传,使用transferFrom上传应该是类似的。文章声称与传统 I/O 相比,大文件传输速度提高了 65%。但这可能取决于您的网络连接的特性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-17
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多