Java Dateidownloads mit Gesamtfortschritt & Dateifortschritt

JavaGamer

Bekanntes Mitglied
Hallo,

ich hätte da ein Problem:

Ich habe eine ArrayList die gefüllt mit Einträgen (Strings) ist. Diese stammen aus einer externen Datei. Nun möchte ich gerne dass alle Dateien in einen bestimmten Ordner, den man selbst auswählen kann hineingedownloaded und gespeichert werden.
Dazu habe ich 2 JProgressBars, da ich gernen den Fortschritt der einzelnen Datei und den Gesamtfortschritt angezeigt haben möchte. Obendrein möchte ich dabei noch den Dateinamen angezeigt bekommen.

Mein Problem ist jetzt eigentlich wie ich das mit den JProgressBars mache und mit dem Anzeigen des Namens. Zudem weiß ich nicht wie ich die Dateien in ein vom User definierbares Verzeichnis downloaden soll.

Ich hoffe jemand kann mir hierbei helfen.
JavaGamer
 
Schritt für Schritt! Versuche nicht immer alles aufeinmal zu machen 🙂

Hast du schon probiert einen Dateidownload ohne UI zu realisieren?
Wenn dieser klappt kann man sich über die Einbindung an eine UI Gedanken machen.

Was hast du dir schon für Gedanken zum Download gemacht? Schon Codeschnipsel?
 
Zuletzt bearbeitet:
Schritt für Schritt! Versuche nicht immer alles aufeinmal zu machen 🙂

Hast du schon probiert einen Dateidownload ohne UI zu realisieren?
Wenn dieser klappt kann man sich über die Einbindung an eine UI Gedanken machen.

Was hast du dir schon für Gedanken zum Download gemacht? Schon Codeschnipsel?
Also die Gui hab ich fertig (bis auf die ProgressBars). Einen Download ohne Progress-Bar hatte ich schon mal realisiert, ist aber schon ewigkeiten her.

Also an Gedanken, nun ja, es soll Datei für Datei gedownloaded werden aber wahrscheinlich muss ich wohl vorher alle links einmal aufrufen damit ich die Gesamtgröße kenne und somit einen Gesamtfortschritt anzeigen kann.
Zudem müsste ich die Datei an einem bestimmten Pfad speichern, die Varialbe die diesen Pfad angibt habe ich bereits (gespeichert als File).

Nun ja, Codeschnispel, ich könnte jetzt hier zwar den alten Downloader von mir rauskramen, aber der Code ist so unleserlich, als ich mal versucht habe das Teil abzudaten bin ich an meinem eigenen Code gefailt xD
Sonst hätte ich nur dies hier:
Java:
	public static void downloadFile(ArrayList<String> downloadList, File directory)
	{
		
	}
Und die GUI:
Java:
package minecraftplaye.installer.gui;

import java.io.File;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

import minecraftplaye.installer.handlers.Logger;
import minecraftplaye.installer.lib.Level;

public class DownloadGui
{
	
	private JPanel panel = StartUpGui.panel;
	
	public static JProgressBar current, all;
	private static JLabel currentLabel, allLabel;
	private static File file = new File("Mod 1");
	
	public DownloadGui()
	{
		this.panel.removeAll();
		
		setup();
		add(this.panel);
		
		this.panel.validate();
		this.panel.repaint();
	}
	
	private static void setup()
	{
		all = new JProgressBar();
		all.setStringPainted(true);
		all.setValue(0);
		all.setBounds(50, 50, 300, 20);
		
		current = new JProgressBar();
		current.setStringPainted(true);
		current.setValue(0);
		current.setBounds(50, 150, 300, 20);
		
		allLabel = new JLabel("Gesamtfortschritt:");
		allLabel.setBounds(50, 30, 150, 10);
		
		currentLabel = new JLabel("Fortschritt: " + file.getName());
		currentLabel.setBounds(50, 130, 150, 10);
	}
	
	private static void add(JPanel panel)
	{
		panel.add(all);
		panel.add(current);
		panel.add(allLabel);
		panel.add(currentLabel);
	}
	
	/**
	 * Returns the progress bar for the current mod.
	 */
	public static JProgressBar getCurrentBar()
	{
		return current;
	}
	
	/**
	 * Returns the progress bar of total progressive
	 */
	public static JProgressBar getAllBar()
	{
		return all;
	}
	
	/**
	 * @return The Value of the given progress bar
	 */
	public static int getProgress(JProgressBar bar)
	{
		if(bar == current)
			return current.getValue();
		else if(bar == all)
			return all.getValue();
		
		return 0;
	}
	
	/**
	 * Sets the value of the given progress bar
	 * 
	 * @param bar The progress bar to set the value for
	 * @param value The value
	 */
	public static void setProgress(JProgressBar bar, int value)
	{
		if(bar == current)
			current.setValue(value);
		else if(bar == all)
			all.setValue(value);
		
		if(bar != current && bar != all)
			Logger.log(Level.WARNING, "No progress bar was found to set the value for: " + bar.getName() + " Value: " + value);
		else
			Logger.log(Level.DEBUG, "The Value (" + value + ") for the progress bar " + bar.getName() + " was successfully set.");
	}
}
Ja, ich weiß man arbeitet nicht mit Null-Layout, allerdings kann ich mir so das gesammte Tool optimal zusammenbauen und weiß wenn ich fertig bin welches Layout am besten zum Tool passt. 🙂
Ich denke mal der Code mit dem auslesen der ZIP-Datei, den ich ein wenig erweitert habe muss ich hier nicht posten, da ich übergebe einfach nur die Variablen an die Methode und überprüfe vorher ob diese Variablen nicht null sind.
 
Zuletzt bearbeitet:
Dann schau ob du diesen Code noch wo findest und versuche ihn in deinem Programm einzubauen (ohne Anbindung zur UI!)
Ansonsten einfach im Internet nach ähnlichen Code schauen, und probieren das der Download ohne Anbindung an die UI funktioniert.

Wenn du die Dateien mal downloaden kannst (muss auch noch nicht der richtige Ordner sein) kann man die weiteren Schritte angehen: richtiger Ordner, Fortschritt (1 von x Dateien usw. / 1 von 100%) auf der Konsole ausgeben, Fortschritt in der UI anzeigen.
 
Wenn Du Einzel- und Gesamtfortschritt in zwei getrennten Progressbars anzeigen willst, dann reicht es doch auch, wenn Du in dem Gesamtfortschritts-Bar die Anzahl hochzählst. Dann must du vorher nur wissen wie viele Dateien es sind und nicht von jeder die Größe

Gruß

Claus
 
Ok, habe jetzt mal ein wenig dran rumgebastelt:

Java:
// directory = the directory to save all files in!
	public static void downloadFile(ArrayList<String> downloadList, File directory)
	{
		BufferedInputStream in = null;
		FileOutputStream fout = null;
		URL url = null;
		for(int i = 0; i < downloadList.size(); i++)
		{
			try 
			{
				url = new URL(downloadList.get(i).toString());
				in = new BufferedInputStream(url.openStream());
				fout = new FileOutputStream(url.getFile());
				
				final byte data[] = new byte[1024];
				int cout;
				while((cout = in.read(data, 0, 1024)) != -1)
				{
					fout.write(data, 0, cout);
				}
				
				in.close();
				fout.close();
			} 
			catch (MalformedURLException e)
			{
				e.printStackTrace();
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
		}
	}
Problem ist jetzt, wie update ich die Progressbar... (! NICHT die für den Gesamtfortschritt !).
Da ich muss ja jetzt irgendwie an den Fortschritt des Downloads der Datei kommen, nur wie?
Und dann wäre da noch dass die Datein an einem bestimmten Ort gespeichert werden sollen (der 2. Paramter der Methode), nur ich habe keine Ahnung wie ich dies dem Programm sagen soll.
 
Java:
	public static void downloadFile(ArrayList<String> downloadList, File directory)

Kleine Anmerkung zur Namensgebung 😛
Dein Methode heißt "downloadFile", aber es werden alle Dateien in der Liste geladen 😉
Es würde sich anbieten eine 2.Methode zu schreiben, welche nur die for-Schleife beinhaltet (downloadFiles) und nur die "downloadFile" Methode aufruft.

Java:
	public static void downloadFile(ArrayList<String> downloadList, File directory)
	{
..........
				url = new URL(downloadList.get(i).toString());
				in = new BufferedInputStream(url.openStream());
				fout = new FileOutputStream(url.getFile());
Und dann wäre da noch dass die Datein an einem bestimmten Ort gespeichert werden sollen (der 2. Paramter der Methode), nur ich habe keine Ahnung wie ich dies dem Programm sagen soll.

Wo schreibst du denn die Datei jetzt hin? Was hindert dich daran deine Variable "fout" so zu initialisieren das der Parameter "directory" einbezogen wird?
--> Kombiniere "directory" und "url.getFile()"


Da ich muss ja jetzt irgendwie an den Fortschritt des Downloads der Datei kommen, nur wie?

Schau doch vor dem eigentlichen Download nach wie groß die Datei ist.
Setze "minValue" und "maxValue" der Progressbar und wenn notwendig noch Zwischenschritte.
Mit "setValue" kannst du den aktuellen Wert einer ProgressBar ändern (Achtung nicht den EDT blockieren 😉)
 
Nun ja, FileOutputStream kennt aber kein Argument für den Speicherort. Nur die Datei und wenn man möchte einen boolean, ein Argument für den Speicherort gibt es nicht.

Was meinst du mit EDT? Und mit welcher Methode komme ich an die Größe der Datei und an die Anzahl an bytes die schon gedownloaded wurden?
 
Nun ja, FileOutputStream kennt aber kein Argument für den Speicherort.

Korrekt, aber du kannst dem Stream entweder einen String mitgeben (siehe FileOutputStream - Konstruktor mit String), oder ein Datei Objekt.

Nur die Datei ...... , ein Argument für den Speicherort gibt es nicht.

Woran scheitert es? Eine Datei ist immer über einen bestimmten Pfad erreichbar, dieser kann auch angegeben werden. (siehe Dokumentation)
(Wenn die Datei nicht existiert kann man diese auch erstellen)

Was meinst du mit EDT?

Event Dispatcher Thread, wenn dieser blockiert ist durch eine Schleife, kann sich die UI nicht updaten.
Dadurch siehst du die Zwischenschritte bei der Progressbar nicht.

Und mit welcher Methode komme ich an die Größe der Datei und an die Anzahl an bytes die schon gedownloaded wurden?

Code dazu findet man ganz leicht auf Google 🙂
Für die Dateigröße einfach folgende Stichwörter verwenden: "Java Url get filesize"

Die Methode "read" gibt dir zurück wieviele Bytes gelesen wurden .... einfach mitzählen 🙂
 
Ist das hier so richtig?
Java:
	public static void downloadFiles(ArrayList<String> downloadList, File destination) throws MalformedURLException
	{
		for(int i = 0; i < downloadList.size(); i++)
		{
			downloadFile(new URL(downloadList.get(i).toString()), destination);
			DownloadGui.setProgress(DownloadGui.getAllBar(), i);
		}
	}
	
	private static void downloadFile(URL websiteFile, File destination)
	{
		BufferedInputStream in = null;
		FileOutputStream fout = null;
		URLConnection connection = null;
		int minValue = 0;
		int maxValue = 0;
		try 
		{
			connection = (URLConnection) websiteFile.openConnection();
			
			maxValue = connection.getContentLength();
			
			in = new BufferedInputStream(connection.getInputStream());
			fout = new FileOutputStream(StartUpGui.modpackDir + websiteFile.getFile());
			
			DownloadGui.setLabel(websiteFile.getFile());
			
			final byte data[] = new byte[1024];
			int cout;
			while((cout = in.read(data, 0, 1024)) != -1)
			{
				fout.write(data, 0, cout);
				minValue = in.read();
				DownloadGui.setProgress(DownloadGui.getCurrentBar(), (minValue * 100 ) / maxValue);
			}
			
			in.close();
			fout.close();
		} 
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
	}

Zudem noch eine Frage, wie schaffe ich es diesen Download nun zu pausieren, also das eine Datei gedownloadet wird, dann ein anderes Java-Programm gestartet wird und nach dem das andere Java-Programm geschlossen wurde, der Installer weiter downloadet? ???:L
 
Zuletzt bearbeitet:
Ist das hier so richtig?

Einfach ausprobieren, geht doch schneller als auf die Antwort zu warten oder? 😉

Anmerkung:
Warum gibst du an die Methode "downloadFile" schon eine URL mit und nicht den String? Wenn du mal "downloadFile" direkt aufrufst musst du extra aus dem String ein URL Objekt machen.
Die Einbindung der UI kommt mir zwar etwas komisch vor (da die Methoden statisch sind) aber naja steht hier nicht zur Debatte.

wie schaffe ich es diesen Download nun zu pausieren,

Den Download in einen eigenen Thread auslagern.
Methoden anbieten um den Thread zu pausieren usw.
 
Zuletzt bearbeitet:
Einfach ausprobieren, geht doch schneller als auf die Antwort zu warten oder? 😉

Anmerkung:
Warum gibst du an die Methode "downloadFile" schon eine URL mit und nicht den String? Wenn du mal "downloadFile" direkt aufrufst musst du extra aus dem String ein URL Objekt machen.
Die Einbindung der UI kommt mir zwar etwas komisch vor (da die Methoden statisch sind) aber naja steht hier nicht zur Debatte.



Den Download in einen eigenen Thread auslagern.
Methoden anbieten um den Thread zu pausieren usw.
Ok, irgendwie komme ich beim Thread nicht mehr weiter mit dem pausieren und weiter arbeiten lassen, wenn die andere .jar geschlossen ist.

Zudem wird es durch den Thread nur unübersichtlich.... 🙁 ;(

Java:
	public static void downloadFiles(final ArrayList<String> downloadList, final File destination)
	{
		DownloadGui.setProgressMinMax(DownloadGui.getAllBar(), 0, downloadList.size() + 1);
		DownloadGui.setProgressMinMax(DownloadGui.getCurrentBar(), 0, 100);
		
		Runnable download = new Runnable()
		{
			@Override
			public void run() 
			{
				String url = "http://files.minecraftforge.net/maven/net/minecraftforge/forge/" + DescriptionGui.getMcVersion() 
						+ "-" + DescriptionGui.getForgeVersion() + "/forge-" + DescriptionGui.getMcVersion() 
						+ "-" + DescriptionGui.getForgeVersion() + "-installer.jar";
				
				try
				{
					downloadFile(new URL(url), PathHandler.getPathToMinecraft());
					
					try 
					{
						Runtime.getRuntime().exec(new String[]{"java","-jar",forge.getName()});
					} 
					catch (IOException e)
					{
						Logger.log2(Level.FATAL, e, "Problem beim Starten des Forge-Installers!", "InstallationHandler - MalformedURLException");
					}
					
					if(forge != null && forge.exists())
						forge.delete();
				} 
				catch (MalformedURLException e1)
				{
					Logger.log2(Level.FATAL, e1, url, "InstallationHandler - MalformedURLException");
				}
				
				for(int i = 0; i < downloadList.size(); i++)
				{
					try 
					{
						downloadFile(new URL(downloadList.get(i).toString()), destination);
					} 
					catch (MalformedURLException e) 
					{
						Logger.log2(Level.FATAL, e, downloadList.get(i).toString(), "InstallationHandler - MalformedURLException");
					}
					DownloadGui.setProgress(DownloadGui.getAllBar(), i + 1);
				}
			}
		};
	}

Ist das mit dem starten der .jar eigentlich so richtig? Also ist das so platformunabhängig, dass es auch unter Linux und Mac funktioniert und auch die Datei im .minecraft Ordner findet?

Java:
forge = new File(url.getFile());
Ein kleiner Code-Ausschnitt aus der downloadFile-Methode. Die url (URL) und die url (String) aus beiden Methoden sind identisch, bis auf das es einmal ein String und einmal eine URL ist.
 
Zuletzt bearbeitet:
Ok, irgendwie komme ich beim Thread nicht mehr weiter mit dem pausieren und weiter arbeiten lassen, wenn die andere .jar geschlossen ist.

Wenn dein Dateidownload inkl Fortschrittsanzeige schon funktioniert, dann passts 🙂

Für dein nächstes Thema mach doch bitte wieder einen eigenen Thread auf. Sonst passt der Titel nicht mehr zur Problembehandlung!
 

Zurück
Oben