java.lang.NegativeArraySizeException:-1 使用 URLConnection 在 Android 上下载文件

java.lang.NegativeArraySizeException: -1 downloading file on Android with URLConnection

所以我尝试在我的应用程序中实现这个下载文件的功能,但是我没有成功,想知道为什么。这是代码:

public class Receiver extends BroadcastReceiver {

public static void downloadFile(String url, File outputFile) {
    try {

        URL u = new URL(url);
        URLConnection conn = u.openConnection();
        int contentLength = conn.getContentLength();

        DataInputStream stream = new DataInputStream(u.openStream());

        byte[] buffer = new byte[contentLength];
        stream.readFully(buffer);
        stream.close();

        DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile));
        fos.write(buffer);
        fos.flush();
        fos.close();
    } catch(FileNotFoundException e) {
        Log.i("FileNotFoundException", "file not found"); // swallow a 404
    } catch (IOException e) {
        Log.i("IOException", "io exc"); // swallow a 404
    }
}

Handler handler;

@Override
public void onReceive(Context context, Intent intent) {

    final String link = "https://images.app.goo.gl/zjcreNXUrrihcWnD6";
    String path = Environment.getExternalStorageDirectory().toString()+ "/Downloads";
    final File empty_file = new File(path);

    new Thread(new Runnable() {
        @Override
        public void run() {
            downloadFile(link, empty_file);
        }
    }).start();

}

}

我收到这些错误:

2020-07-07 14:09:23.142 26313-26371/com.example.downloader E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: com.example.downloader, PID: 26313
java.lang.NegativeArraySizeException: -1
    at com.example.downloader.Receiver.downloadFile(Receiver.java:39)
    at com.example.downloader.Receiver.run(Receiver.java:66)
    at java.lang.Thread.run(Thread.java:919)

第 39 行是:

byte[] buffer = new byte[contentLength];

可能主要问题是线程的错误使用。

老实说,我是 Android 的新手,很难解决这个问题,也许你可以在 [=29= 中推荐一些好的 material 或与 Threads/URLs 相关的教程] (我已经搜索了很多,但仍然很难)。当然,对于我做错了什么的直接建议,我将不胜感激。

如果 HTTP 服务器事先不知道响应的大小,它可以发送内容长度为 -1 的响应。

不要分配整个文件大小的缓冲区,而是将其设置为合理的大小(例如 8K 字节)并使用循环流式传输文件;例如

byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0) {
    out.write(buffer, 0, count);
}

这种方法有几个优点。它在内容长度为 -1 时起作用,如果内容长度非常大,它可以保护您免受 OOME 问题。 (不过 检查 内容长度仍然有意义......以避免填满设备文件系统。)


我注意到您当前的版本还有其他问题。

  1. 您正在以可能导致文件描述符泄漏的方式管理流。我建议您了解...并使用... JAVA 8 尝试使用资源 语法。

  2. 这是可疑的:

     Log.i("IOException", "io exc"); // swallow a 404
    

    假设所有 IOException 在那个 catch 块中被捕获都是由于 404 响应是不安全的。评论(至少!)不准确。