我必须为项目制作一个p2p程序。一切正常。我已经设置了客户端可以一次下载多个文件(下载使用线程)。我现在的问题是如何才能真正获得下载的整体进度。我试过这样但是它不起作用
try {
int bytesRead;
InputStream in = mySocket.getInputStream();
DataInputStream clientData = new DataInputStream(in);
OutputStream output = new FileOutputStream(("./download/" + filename));
byte[] buffer = new byte[1024];
int currentProgress = 0;
while (filesize > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, filesize))) != -1) {
output.write(buffer, 0, bytesRead);
filesize -= bytesRead;
currentProgress = (int) ((((double)filesize) / ((double)size)) * 100d);
currentProgress = ((100-currentProgress)/ViewClient.countFiles);
System.out.println(currentProgress);
}
output.close();
in.close();
System.out.println("File "+filename+" received from client.");
} catch (IOException ex) {
ex.printStackTrace();
}
这个每个值(0,1,2,3)将打印100次然后我的进度条有时会达到2'000'000取决于文件。如何获取整体下载的内容? 提前谢谢
答案 0 :(得分:2)
从概念上讲,您有n
个任务,每个任务都会产生0到100%之间的进度。
为了简单起见,我将使用0-1作为进度值的想法。
您接受每项任务的进度并对其求和,然后将其除以任务数量,这将为您提供0-1
之间的所有进度,例如......
int taskCount = 10;
List<Double> taskProgress = new ArrayList<>(taskCount);
for (int index = 0; index < taskCount; index++) {
taskProgress.add(0.0);
}
double overallProgress = 0;
int round = 0;
do {
round++;
double sum = 0;
for (int index = 0; index < taskCount; index++) {
double progress = taskProgress.get(index);
progress += Math.random() * 0.1;
progress = Math.min(progress, 1.0);
sum += progress;
taskProgress.set(index, progress);
}
overallProgress = sum / (double)taskCount;
System.out.println("[" + round + "] " + NumberFormat.getPercentInstance().format(overallProgress) + "; " + NumberFormat.getNumberInstance().format(overallProgress));
} while (overallProgress < 1.0);
哪个可以打印......
[1] 5%; 0.049
[2] 9%; 0.09
[3] 14%; 0.144
[4] 18%; 0.179
[5] 23%; 0.23
[6] 28%; 0.276
[7] 32%; 0.321
[8] 37%; 0.366
[9] 40%; 0.403
[10] 45%; 0.451
[11] 51%; 0.505
[12] 55%; 0.552
[13] 60%; 0.601
[14] 64%; 0.642
[15] 69%; 0.695
[16] 76%; 0.761
[17] 80%; 0.803
[18] 84%; 0.845
[19] 87%; 0.869
[20] 90%; 0.902
[21] 92%; 0.925
[22] 95%; 0.946
[23] 96%; 0.962
[24] 97%; 0.971
[25] 98%; 0.976
[26] 99%; 0.986
[27] 99%; 0.989
[28] 99%; 0.993
[29] 100%; 1
更新了基于Swing的示例
因此,这基本上使用SwingWorker
来执行后台任务,这基本上将进度值递增一个随机量(然后暂停一段随机时间)。工作人员通过其publish
/ process
方法提供进度更改通知,该方法向感兴趣的各方提供通知,但是在事件调度线程的上下文中提供通知。
该示例使用了一个简单的interface
,它被传递给SwingWorker
,以允许它向另一方提供有关进度状态更改的通知。然后,用户界面会在Map
中维护有关每个工作人员进度的信息,该信息用于计算sum
以及由此产生的总进度。基本上是相同的概念,只是在一个更动态的例子中
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ProgressTest {
public static void main(String[] args) {
new ProgressTest();
}
public ProgressTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements ProgressMonitor{
private Map<DownloadWorker, Double> workerProgress;
private int taskCount;
private double progress;
public TestPane() {
workerProgress = new HashMap<>(25);
taskCount = 10;
for (int index = 0; index < 10; index++) {
DownloadWorker worker = new DownloadWorker(index, this);
workerProgress.put(worker, 0d);
worker.execute();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = (int)Math.round(getWidth() * progress);
g2d.setColor(UIManager.getColor("ProgressBar.selectionBackground"));
g2d.fillRect(0, 0, width, getHeight());
g2d.dispose();
}
@Override
public void progressWasUpdated(DownloadWorker worker, double progress) {
workerProgress.put(worker, progress);
double sum = 0;
for (Map.Entry<DownloadWorker, Double> entry : workerProgress.entrySet()) {
sum += entry.getValue();
}
this.progress = sum / (double)taskCount;
repaint();
}
}
public interface ProgressMonitor {
public void progressWasUpdated(DownloadWorker worker, double progress);
}
private Random rnd = new Random();
public class DownloadWorker extends SwingWorker<Void, Double> {
private int index;
private ProgressMonitor progressMonitor;
public DownloadWorker(int index, ProgressMonitor progressMonitor) {
this.progressMonitor = progressMonitor;
this.index = index;
}
@Override
protected Void doInBackground() throws Exception {
double progress = 0;
do {
progress += Math.random() * 0.1;
progress = Math.min(progress, 1.0);
publish(progress);
Thread.sleep(rnd.nextInt(490) + 10);
} while (progress < 1.0);
publish(1.0);
System.out.println(index + " has ended");
return null;
}
public int getIndex() {
return index;
}
@Override
protected void process(List<Double> chunks) {
progressMonitor.progressWasUpdated(this, chunks.get(chunks.size() - 1));
}
}
}
出于示例的目的,每个worker都提供了一个int
索引,这可用于提供一些额外的调试,以便您可以看到每个更新的方式