2016-07-09 22 views
0

Ich möchte eine Datei von einer URL herunterladen. Die Dateigröße beträgt 564,31 MB. Ich habe keine Ahnung, welcher Fehler hier vorgeht. Außerdem frage ich mich, ob mein Code der richtige Weg ist, um eine Datei von einer URL herunterzuladen. Wenn es einen besseren Weg gibt, sag mir bitte im Detail, warum es besser ist. Vielen Dank.java.lang.OutOfMemoryError: Java-Heapspeicher beim Herunterladen einer großen Datei von einer URL

import org.apache.commons.io.FilenameUtils; 
import java.io.*; 
import java.net.MalformedURLException; 
import java.net.URL; 

/** 
* Created by lukas on 6/30/16. 
*/ 
public class Main { 
    public static void main(String[] args){ 
     try { 
      String link = "https://s.basketbuild.com/uploads/devs/dianlujitao/oneplus3/cm13/cm-13.0-20160621-UNOFFICIAL-oneplus3.zip"; 
      URL url = new URL(link); 
      InputStream inputStream = new BufferedInputStream(url.openStream()); 
      ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
      int n=0; 
      byte[] buf = new byte[1024]; 
      long duration = System.currentTimeMillis(); 
      while((n=inputStream.read(buf))!=-1){ 
       byteArrayOutputStream.write(buf, 0, n); 
      } 
      duration = System.currentTimeMillis()-duration; 
      System.out.println("Finish in "+duration+"ms"); 

      inputStream.close(); 

      File dir = new File("Output path"); 
      if(!dir.exists()) 
       dir.mkdirs(); 

      String fileBaseName = FilenameUtils.getBaseName(link); 
      String fileExtension = FilenameUtils.getExtension(link); 
      System.out.println("Name: "+fileBaseName+'.'+fileExtension); 
      File outputFile = new File(dir, fileBaseName+'.'+fileExtension); 

      if(!outputFile.exists()){ 
       outputFile.createNewFile(); 
      } 

      FileOutputStream fileOutputStream = new FileOutputStream(outputFile); 
      fileOutputStream.write(byteArrayOutputStream.toByteArray()); 

      //release outputstream 
      byteArrayOutputStream.close(); 
      fileOutputStream.close(); 

      System.out.println("Your download has been finished"); 


     } catch (MalformedURLException e) { 
      e.printStackTrace(); 
      System.out.println("Something unexpected has happened!"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
      System.out.println("Something unexpected has happened!"); 
     } 


    } 
} 

Hier ist, was meine Konsole sagt:

Finish in 133506ms 
Name: cm-13.0-20160621-UNOFFICIAL-oneplus3.zip 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
    at java.util.Arrays.copyOf(Arrays.java:3236) 
    at java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:191) 
    at Main.main(Main.java:42) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) 
+0

Mögliches Duplikat von [Wie behandeln "java.lang.OutOfMemoryError: Java Heap-Speicher" Fehler (64 MB Speichergröße)] (http://stackoverflow.com/questions/37335/how-to-deal -with-java-lang-outofmemoryerror-java-haufenraumfehler-64mb-heap) –

+0

Willkommen bei SO. Es ist eine gute Idee, nach möglichen Antworten zu suchen, bevor Sie Zeit damit verbringen, eine Frage zu stellen. Normalerweise googelt man nur die Hauptfehlermeldung (in diesem Fall ist es 'java.lang.OutOfMemoryError: Java heap space'). –

+0

Und das sind 2 Fragen. Es ist am besten, sie getrennt zu halten. In der Regel bekommen die Fragen "Wie man das besser macht" nicht viele Antworten, weil wir nicht dafür da sind. Bitte lesen Sie [fragen] und [antworten]. –

Antwort

3
  1. ByteArrayOutputStream ordnet alle seine Daten im Heap-Speicher. Der richtige Weg ist, um die Datei direkt zu schreiben, und verwenden Sie einen Puffer für die so Disk-I/O wird optimiert:

    OutputStream os = new BufferedOutputStream(new FileOutputStream("myFile.txt"));
  2. System.currentTimeMillis() gibt Ihnen das aktuelle Datum und die Uhrzeit, die ändern irgendein Punkt. Es ist nicht beabsichtigt, Dauer zu berechnen, verwenden Sie SystemClock.nanoTime() dafür.

+0

Verwenden Sie hier keinen 'BufferedOutputStream'. Weisen Sie einen Puffer mit fester Größe zu und lesen und schreiben Sie die Daten in Blöcken. – erickson

+1

@erickson Das ist was genau BufferedOutputStream tut. Ihre Methode garantiert nicht, dass der Block voll ist, das Lesen von Daten aus dem Netzwerk kann sogar ein Byte nach dem anderen zurückgeben. Unbuffered Disk I/O ist Overkill. –

+0

Es muss nicht garantiert werden, dass der Block voll ist. Single-Byte-Netzwerk liest beim Herunterladen einer Datei wäre pathologisch. Redundantes Kopieren ist Overkill. – erickson