2016-07-09 77 views
0

我想從URL下載文件。文件大小爲564.31MB。我不知道這裏發生了什麼錯誤。另外,我想知道我的代碼是否是從URL下載文件的正確方式。如果有更好的方法,請詳細告訴我爲什麼它比這更好。謝謝。java.lang.OutOfMemoryError:從URL下載大文件時的Java堆空間

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!"); 
     } 


    } 
} 

這裏是我的控制檯說什麼:

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

可能的重複[如何處理「java.lang.OutOfMemoryError:Java堆空間」錯誤(64MB堆大小)](http://stackoverflow.com/questions/37335/how-to-deal -with-java-lang-outofmemoryerror -java-heap-space-error-64mb-heap) –

+0

歡迎來到SO。在花時間寫問題之前尋找可能的答案是一個好主意。通常只要使用googling的主要錯誤信息(在這種情況下,它是'java.lang.OutOfMemoryError:Java heap space')。 –

+0

而且,這是2個問題。最好讓他們分開。通常,「如何做得更好」這個問題不會得到很多答案,因爲這不是我們在這裏做的。請閱讀[問]和[答案]。 –

回答

3
  1. ByteArrayOutputStream堆內存中分配其所有數據。正確的方法是直接寫入文件,並使用緩衝區對於這樣的磁盤I/O進行了優化:

    OutputStream os = new BufferedOutputStream(new FileOutputStream("myFile.txt"));
  2. System.currentTimeMillis的()爲您提供當前的日期和時間,這可能會在改變任何一點。這並不意味着要計算持續時間,請使用SystemClock.nanoTime()。

+0

這裏不要使用BufferedOutputStream。分配一個固定大小的緩衝區,並以此塊讀取和寫入數據。 – erickson

+1

@erickson這是BufferedOutputStream的功能。你的方法不能保證數據塊完整,從網絡上讀取數據甚至可以一次返回一個字節。無緩衝的磁盤I/O是矯枉過正的。 –

+0

沒有必要保證塊已滿。下載文件時單字節網絡讀取將是病態的。冗餘複製是矯枉過正的。 – erickson

相關問題