Reputation: 158
I have to make a little p2p programm for a project. Everything works fine. I have set it up that the client can download multiple files at once(download use threads). My issue is now how can I actually get the overall progress of the download. I tried like this but it doesnt work
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();
}
with this each value(0,1,2,3) will be printed like 100 times and then my progress bar goes sometime up to 2'000'000 depends on the files. How can I get the overall downloaded content? Thank you in advance
Upvotes: 0
Views: 1403
Reputation: 347334
Conceptually, you have n
number of task, each which will generate a progress of between 0-100%.
To make things simple, I'll work with the the idea of 0-1 as the progress value.
You take the progress of each task and sum it, you then divide this by the number of tasks, which will give you an over all progress of between 0-1
, for example...
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);
Which could print...
[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
Updated with Swing based example
So, this basically uses a SwingWorker
to perform a background task, this basically increments a progress value by a random amount (and then pauses for a random amount of time). The worker provides notification of the progress change via it's publish
/process
methods, which provides notification back to interested parties, but does so from within the context of the Event Dispatching Thread.
The example makes use of a simple interface
, which is passed to the SwingWorker
to allow it to provide notification back to another party about changes to the progress state. The UI then maintains information about each worker's progress in a Map
, which is used to calculate the sum
and resulting total progress. Essentially the same concept above, just in a more dynamic example
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));
}
}
}
For the purpose of the example, each worker is provide with a int
index, this can be used to provide some additional debugging so you can see how each is updated
Upvotes: 2