Android下载文件时遇到内存不足的问题

5

我正在尝试下载一个刚好小于 22MB 的 zip 文件,但在开始时就遇到了问题。尽管更改了默认的 BufferedInputStream,但仍然出现了内存不足的错误。

public void downloadFromUrl(String fileName) {

        //avoid unknown host exception
        try {

            InetAddress i = InetAddress

                    .getByName("http://xxx/Android/" + fileName);

        } catch (UnknownHostException e1) {

            e1.printStackTrace();

        }

        try {

            URL url = new URL("http://xxx/Android/" + fileName);
            File file = new File(fileName);

            long startTime = System.currentTimeMillis();
            Log.d("DownloadManager", "download begining");
            Log.d("DownloadManager", "download url:" + url);
            Log.d("DownloadManager", "downloaded file name:" + fileName);

            URLConnection ucon = url.openConnection();

            InputStream is = ucon.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(is, 23 * 1024);

            ByteArrayBuffer baf = new ByteArrayBuffer(23 * 1024);
            int current = 0;
            while ((current = bis.read()) != -1) {

                baf.append((byte) current);

            }

            FileOutputStream fos = new FileOutputStream(file);
            fos.write(baf.toByteArray());
            fos.close();
            Log.d("DownloadManager",
                    "download ready in"
                            + ((System.currentTimeMillis() - startTime) / 1000)
                            + " sec");

        } catch (IOException e) {

            Log.d("DownloadManager", "Error: " + e);

        }

    }

堆栈:

10-28 10:18:16.885: DEBUG/ImageManager(1804): download begining
10-28 10:18:16.885: DEBUG/ImageManager(1804): download url:http://xxx/Android/Samples.zip
10-28 10:18:16.885: DEBUG/ImageManager(1804): downloaded file name:Samples.zip
10-28 10:18:17.204: INFO/global(1804): Default buffer size used in BufferedInputStream constructor. It would be better to be explicit if an 8k buffer is required.
10-28 10:18:17.845: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 1803 objects / 185168 bytes in 96ms
10-28 10:18:18.415: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 229 objects / 105296 bytes in 78ms
10-28 10:18:18.425: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 3.184MB for 376848-byte allocation
10-28 10:18:18.545: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 109ms
10-28 10:18:20.555: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 44 objects / 190080 bytes in 65ms
10-28 10:18:20.575: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 3.721MB for 753680-byte allocation
10-28 10:18:20.675: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 95ms
10-28 10:18:22.725: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 376904 bytes in 66ms
10-28 10:18:23.145: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 4.799MB for 1507344-byte allocation
10-28 10:18:23.245: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 95ms
10-28 10:18:25.415: WARN/ActivityManager(59): Launch timeout has expired, giving up wake lock!
10-28 10:18:26.205: WARN/ActivityManager(59): Activity idle timeout for HistoryRecord{43ef1378 com.xxx.xxxe/.TabViewMain}
10-28 10:18:27.995: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 753736 bytes in 65ms
10-28 10:18:28.655: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 6.956MB for 3014672-byte allocation
10-28 10:18:28.765: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 102ms
10-28 10:18:33.275: DEBUG/dalvikvm(123): GC_EXPLICIT freed 833 objects / 48984 bytes in 2059ms
10-28 10:18:37.275: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 1507400 bytes in 69ms
10-28 10:18:38.115: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 11.268MB for 6029328-byte allocation
10-28 10:18:38.275: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 151ms
10-28 10:18:53.885: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 3014728 bytes in 70ms
10-28 10:18:53.895: INFO/dalvikvm-heap(1804): Forcing collection of SoftReferences for 12058640-byte allocation
10-28 10:18:54.055: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 158ms
10-28 10:18:54.055: ERROR/dalvikvm-heap(1804): Out of memory on a 12058640-byte allocation.

编辑:好的,我能够使用这个例子,但即使拥有正确的权限,我还是遇到了"permission denied"错误:

`10-2`8 11:33:15.478: WARN/System.err(1781): java.io.FileNotFoundException: /mnt/sdcard/testDirectory/Samples.zip (Permission denied)

1
为什么要将它完全下载到RAM中?我认为你对java.io不是很熟悉。换句话说,你的问题并不是特定于Android的。 - Albus Dumbledore
绝对是Java新手,还在学习什么意思。没有意识到ByteArrayBuffer被发送到RAM,以为它被发送到SD卡! - user375566
3个回答

7

毫不奇怪,你试图将一个22MB的字节数组加载到手机内存中;大多数安卓手机没有那么多内存。你需要做的是将文件流式传输到SD卡或内部存储器中:

// untested
final int BUFFER_SIZE = 23 * 1024;
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
FileOutputStream fos = new FileOutputStream(file);
byte[] baf = new byte[BUFFER_SIZE];
int actual = 0;
while (actual != -1) {
    fos.write(baf, 0, actual)
    actual = bis.read(baf, 0, BUFFER_SIZE);
}

fos.close();

嗯...这给了我一个java.io.file未找到的异常(只读文件系统)。 - user375566
@user375566:确保您的应用程序具有适当的权限来写入文件 http://developer.android.com/guide/topics/security/security.html ,并且您应该决定是要使用内部存储还是外部存储 http://developer.android.com/guide/topics/data/data-storage.html。 - Lie Ryan
我正在使用外部程序,并且我认为我拥有所有必要的权限。 - user375566
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> - user375566
已编辑以实现半工作能力,但仍存在权限错误。 - user375566
显示剩余2条评论

5

这里有一个下载大文件的小方法,经过 Lie Ryan 的测试并得到启发(感谢他),使用 FileOutputStream 刷新缓冲区。

public void DownloadFromUrl(String fileURL, String fileName) {  //this is the downloader method
       try {
               URL url = new URL( fileURL); 
               File file = new File(fileName);
               file.createNewFile();
               long startTime = System.currentTimeMillis();
               Log.d("DownloadManager", "download begining");
               Log.d("DownloadManager", "download url:" + url);
               Log.d("DownloadManager", "downloaded file name:" + fileName);
               /* Open a connection to that URL. */
               URLConnection ucon = url.openConnection();

               /*
                * Define InputStreams to read from the URLConnection.
                */
               InputStream is = ucon.getInputStream();

               /*
                * Read bytes to the Buffer until there is nothing more to read(-1) and write on the fly in the file.
                */
               FileOutputStream fos = new FileOutputStream(file);
               final int BUFFER_SIZE = 23 * 1024;
               BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
               byte[] baf = new byte[BUFFER_SIZE];
               int actual = 0;
               while (actual != -1) {
                   fos.write(baf, 0, actual);
                   actual = bis.read(baf, 0, BUFFER_SIZE);
               }

               fos.close();
               Log.d("DownloadManager", "download ready in"
                               + ((System.currentTimeMillis() - startTime) / 1000)
                               + " sec");

       } catch (IOException e) {
               Log.d("DownloadManager", "Error: " + e);
       }

}

1
为什么要使用ByteArrayBuffer?这就是问题所在,你试图将22mb存储在其中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接