Downloader: pause() und resume()

datenmuell

Grünschnabel
Hallo zusammen,

ich bin dabei, einen unterbrechungsfreien Downloader zu erstellen, stoße leider jedoch auf ein Problem. Im Prinzip wird dem Download bei unterbrochener Verbindung mitgeteilt, dass er pausieren soll. Sobald die Verbindung (oder eine andere Verbindung) wieder aktiv ist, soll resumed werden. Der Pause-Status wird in einer globalen Variablen [vars.getPause_download()] gespeichert, auf welche die Klasse zur Überwachung der Verbindungen als auch die Klasse zum Download per Getter/Setter zugreifen kann.

Das Problem besteht nun darin, dass bei Unterbrechung der Verbindung und Durchführung einer Pause und eines Resumes die zu ladende Datei defekt ist. Die Dateigröße stimmt jedoch! Falls die Verbindung nicht unterbrochen wird, funktioniert der Download problemlos.

Hier die Routine, die die Downloads aus der Queue liest und dem Downloader übergibt:
Java:
public class Download_Manager extends Thread
{
	...
	public void run()
	{
		System.out.println("DoM started!");
		URL myUrl = null;
		
		while(true)
		{
			if(vars.getProcessQueueSize() > 0) // Queue abarbeiten, falls etwas drin ist
			{
				try
				{
					myUrl = new URL(vars.getAndRemoveFromProcessQueue());
					System.out.println("DoM reports: Sending download task of '" + myUrl + "' to Downloader!");
				}
				catch (MalformedURLException e)
				{
					e.printStackTrace();
				}
				
				Download myDownload = new Download(myUrl, vars);
				
				while(true) // horche auf pausen oder resumes
				{
					if(vars.getPause_download() == 1 && myDownload.getStatus() == 0)
					{
						myDownload.pause();
					}
					else if(vars.getPause_download() == 0 && myDownload.getStatus() == 1)
					{
						myDownload.resume();
					}
					
					if (myDownload.getStatus() == 2)
						break;
				}
				System.out.println("DoM reports: Download of '" + myUrl + "' finished!");
			}
		}
		
	}
}


Hier der Downloader:
Java:
class Download extends Observable implements Runnable
{
	...

	public static final int DOWNLOADING = 0;
	public static final int PAUSED = 1;
	public static final int COMPLETE = 2;
	public static final int CANCELLED = 3;
	public static final int ERROR = 4;
	private URL url; // download URL
	private int size; // size of download in bytes
	private int downloaded; // number of bytes downloaded
	private int status; // current status of download

	// Constructor for Download.
	public Download(URL url, Variables var)
	{
		vars = var;
		this.url = url;
		size = -1;
		downloaded = 0;
		status = DOWNLOADING;

		// Begin the download.
		download();
	}

	// Get this download's URL.
	public String getUrl()
	{
		return url.toString();
	}

	// Get this download's size.
	public int getSize()
	{
		return size;
	}

	// Get this download's progress.
	public float getProgress()
	{
		return ((float) downloaded / size) * 100;
	}

	public int getStatus()
	{
		return status;
	}

	public void pause()
	{
		status = PAUSED;
	}

	public void resume()
	{
		status = DOWNLOADING;
		download();
	}

	public void cancel()
	{
		status = CANCELLED;
	}

	private void error()
	{
		status = ERROR;
	}

	private void download()
	{
		Thread thread = new Thread(this);
		thread.start();
	}

	// Get file name portion of URL.
	private String getFileName(URL url)
	{
		String fileName = url.getFile();
		return fileName.substring(fileName.lastIndexOf('/') + 1);
	}

	// Download file.
	public void run()
	{
		RandomAccessFile file = null;
		InputStream stream = null;

		try
		{
			// Open connection to URL.
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();

			// Specify what portion of file to download.
			connection.setRequestProperty("Range", "bytes=" + downloaded + "-");

			// Connect to server.
			connection.connect();

			// Make sure response code is in the 200 range.
			if (connection.getResponseCode() / 100 != 2)
			{
				error();
			}

			// Check for valid content length.
			int contentLength = connection.getContentLength();
			if (contentLength < 1)
			{
				error();
			}

			//Set the size for this download if it hasn't been already set
			if (size == -1)
			{
				size = contentLength;
			}

			// Open file and seek to the end of it.
			file = new RandomAccessFile(getFileName(url), "rw");
			file.seek(downloaded);

			stream = connection.getInputStream();
			while (status == DOWNLOADING)
			{
				// Size buffer according to how much of the file is left to download.
				byte buffer[];
				if (size - downloaded > MAX_BUFFER_SIZE)
				{
					buffer = new byte[MAX_BUFFER_SIZE];
				}
				else
				{
					buffer = new byte[size - downloaded];
				}

				// Read from server into buffer.
				int read = stream.read(buffer);
				if (read == -1)
					break;
				
				// Write buffer to file.
				file.write(buffer, 0, read);
				downloaded += read;

				//TODO: Datei fehlerhaft bei Handover
			}
			//System.out.println("ENDE DES DOWNLOADS");

			// setze Status auf COMPLETE, wenn beendet
			if (status == DOWNLOADING)
			{
				status = COMPLETE;
			}
		}
		catch (Exception e)
		{
			System.out.println("Error!");
			error();
		}
		finally
		{
			// Close file.
			if (file != null)
			{
				try
				{
					file.close();
				}
				catch (Exception e)
				{
					System.out.println("File close error!");
				}
			}

			// Close connection to server.
			if (stream != null)
			{
				try
				{
					stream.close();
				}
				catch (Exception e)
				{
					System.out.println("Stream close error!");
				}
			}
		}
	}
}

Ich hoffe, mir kann jemand bei diesem Problem helfen.
Danke schonmal für Eure Mühe!
 
Zuletzt bearbeitet:
Vergleich doch mal die Dateien in nem Texteditor oder besser Hex-Editor: Die komplett runtergeladene und die kaputte und schau wo sie sich unterscheiden.
 
Danke für die Antwort!

Das habe ich schon. Die Dateien unterscheiden sich ab der Stelle, ab welcher wieder resumed wurde.
Es scheint also, dass der Resume nicht an der richtigen Stelle ansetzt.
Ich sehe leider nur nicht, was im Programmcode diesen Fehler verursacht.
 

Neue Beiträge

Zurück