简体   繁体   中英

Download large files using large byte array causes “Out of memory”

I want to download a 100MB file using streams:
I used an AsyncTask class to make download:

    @Override
    protected Void doInBackground(String... params) {
        try {
            URL url = new URL(params[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            inputStream = connection.getInputStream();
            outputStream = new FileOutputStream(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), params[1]));
            byte[] data = new byte[104857600];
            int length = inputStream.read(data);
            outputStream.write(data, 0, length);
        } catch (Exception e) {
            Log.e(TAG, "Unable to download file with DownloadTask: " + e.getMessage());
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                connection.disconnect();
            } catch (Exception e) {
                Log.e(TAG, "Unable to cancel download file with DownloadTask: " + e.getMessage());
            }
        }
        return null;
    }

I'm sure I used the following permissions:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

But when I test my app, it crashes and I see in logcat Out of memory on a 104857616-byte allocation :

10-02 10:28:35.578 29630-2246/com.example.myapp E/dalvikvm-heap: Out of memory on a 104857616-byte allocation.
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime: java.lang.RuntimeException: An error occured while executing doInBackground()
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$3.done(AsyncTask.java:299)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:239)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:856)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:  Caused by: java.lang.OutOfMemoryError
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at com.example.myapp.DownloaderActivity$DownloadTask.doInBackground(DownloaderActivity.java:126)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at com.example.myapp.DownloaderActivity$DownloadTask.doInBackground(DownloaderActivity.java:107)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$2.call(AsyncTask.java:287)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:234)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:856)

Is there some way to download large files or accept 104857600 bytes (100MB)?

You have write data portion by portion as chunk. System don't provide huge memory at once for an operation.

Replace those lines:

byte[] data = new byte[104857600];
int length = inputStream.read(data);
outputStream.write(data, 0, length);

by:

byte [] buffer = new byte[1024];
int bytesRead = 0;
while((bytesRead =input.read(buffer)) != -1) {
outputStream .write(buffer, 0,
bytesRead);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM