【问题标题】:Android:"Unexpected end of stream" exception downloading large filesAndroid:“Unexpected end of stream”异常下载大文件
【发布时间】:2011-11-16 04:19:18
【问题描述】:

我正在构建一个 Android 应用程序,我需要从一个 33 MB 大的 url 下载文件。

这里是下载任务:

try {
            int MAX_BUFFER_SIZE = 4096;
            URL mUrl = new URL(params[0]);
            HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
            connection.setRequestMethod("GET");
            long length = connection.getContentLength(), downloaded = 0;
            int read;
            byte [] buffer = new byte[(((int)length) > MAX_BUFFER_SIZE) ? MAX_BUFFER_SIZE : (int)length];
            String filename = getFilename(mUrl);
            File file = new File (SDCARD_ROOT);
            if (!file.exists() || !file.isDirectory()){
                file.mkdir();
            }
            this.filename = filename;
            file = new File (SDCARD_ROOT + this.filename);  
            FileOutputStream fos = new FileOutputStream (file);
            //Start downloading
            InputStream stream = connection.getInputStream();

            while ((read=stream.read(buffer)) > -1){
                fos.write(buffer, 0, read);
                downloaded += read;
                publishProgress((int) ((float) downloaded/length * 100));
            }
            fos.close();
            return 1;
        } catch (Exception e){
            Log.e("REV-PARTS", "Revolver parts error in DownloadTask: " + e.getMessage());  
            return 2;
        }

它适用于小文件 (1-15 MB),但对于大文件,它会返回“意外的流结束”异常。

【问题讨论】:

  • 哪个调用会引发异常? stream.read()?
  • @Gnufabio 你能解决这个问题吗?
  • 发件人意外关闭了连接。除了删除部分下载之外,您对此无能为力。注意你不需要计算缓冲区大小的所有垃圾。只需使用 8192。将其与数据大小相关联没有任何优势。您的代码仍然可以工作。
  • 你有什么答案吗?你能帮我吗
  • 这似乎是 Android Emulator for Windows 中的一个错误。在 Mac OS 上的 Device 和 Android Emulator 中同样可以正常工作

标签: java android download inputstream


【解决方案1】:

对于大文件,您需要使用以下代码手动设置连接超时。 我已将超时设置为 3 分钟

   connection.setConnectTimeout(180000);
   connection.setReadTimeout(180000);

【讨论】:

  • 这将如何解决“流的意外结束”问题?
  • 下载时由于超时出现此错误,
  • 不,不会,也不会。
【解决方案2】:

我有一个答案。 你应该为你的连接添加一个标题。

connection.setRequestProperty("Accept-Encoding", "identity");

这会对你有帮助。如果有帮助,请说我......

【讨论】:

    【解决方案3】:

    设置块大小似乎对我有用。

    connection.setChunkedStreamingMode(1048576);
    

    【讨论】:

    • 在 Android 9 上对我没有帮助,仍然随机出现“Unexpected end of stream”
    【解决方案4】:

    当你捕获异常时,我尝试downContinue() 方法。我可以显示我的代码:

    private void downloadApk() {
        thread1 = new Thread() {
            public void run() {
                File oFile = null;
                try {
                    URL url = new URL(PQGLApplication.resrootURL + "apk/PQGLMap.apk");
                    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                    ReadableByteChannel channel =
                            Channels.newChannel(urlConnection.getInputStream());
                    oFile =
                            new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                                    + "/" + "hy_ht_new/" + "test2" + ".apk");
                    oFile.setWritable(true);
                    oFile.setReadable(true);
                    if (oFile.exists()) {
                        oFile.delete();
                    }
                    FileOutputStream fos = new FileOutputStream(oFile);
                    fileSize = urlConnection.getContentLength();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int noOfBytes = 0;
                    byte[] data = null;
                    sendApkMessage(0, 0);
                    while ((noOfBytes = channel.read(buffer)) > 0) {
                        data = new byte[noOfBytes];
                        System.arraycopy(buffer.array(), 0, data, 0, noOfBytes);
                        buffer.clear();
                        fos.write(data, 0, noOfBytes);
                        downLoadFileSize += noOfBytes;
                        sendApkMessage(1, downLoadFileSize);
                    }
                    fos.flush();
                    fos.close();
                    channel.close();
                    sendApkMessage(2, oFile.getAbsolutePath());
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    downContinue();
                }
            };
        };
        thread1.start();
    }
    
    private void downContinue() {
        continueTime++;
        try {
            if (continueTime == 3) {
                continueTime = 0;
                sendApkMessage(4, 0);
                Log.e("what is the continuetime", "continueTime" + continueTime);
            } else {
                URL url = new URL(PQGLApplication.resrootURL + "apk/PQGLMap.apk");
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                File oFile =
                        new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/"
                                + "hy_ht_new/" + "test2" + ".apk");
                RandomAccessFile oSavedFile = new RandomAccessFile(oFile, "rw");
                FileOutputStream fos = new FileOutputStream(oFile);
                ReadableByteChannel channel = Channels.newChannel(urlConnection.getInputStream());
                // oSavedFile.seek(nPos);
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                byte[] data = null;
                int temp = 0;
                sendApkMessage(3, oFile.getAbsolutePath());
                while ((temp = channel.read(buffer)) > 0) {
                    data = new byte[temp];
                    System.arraycopy(buffer.array(), 0, data, 0, temp);
                    buffer.clear();
                    fos.write(data, 0, temp);
                }
                fos.flush();
                fos.close();
                oSavedFile.close();
                sendApkMessage(2, oFile.getAbsolutePath());
                continueTime = 0;
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            Log.e("what is the exception", e.toString() + continueTime);
            downContinue();
        }
    
    }
    

    这个downContinue方法就是用来解决这个问题的。至少,文件下载成功!

    【讨论】:

    • 你能解释一下 sendApkMessage() 方法,它到底在做什么?
    • 您不需要将输出文件设置为可读或可写或如果存在则预先删除它。 new FileOutputStream() 已经具备所有这些效果。你也不需要System.arraycopy()。方法依赖于未指定的外部代码。
    猜你喜欢
    • 2017-06-24
    • 2016-10-21
    • 2018-02-19
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    相关资源
    最近更新 更多