Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 解压png文件时有时会出现线程阻塞_Java_Android - Fatal编程技术网

Java 解压png文件时有时会出现线程阻塞

Java 解压png文件时有时会出现线程阻塞,java,android,Java,Android,我正在开发一个android应用程序,需要从Web服务器下载一个带有少量徽标(平均大小为20-30KB的png文件)的zip文件(最大约1.5MB) 我已经在AsyncTask的doInbackground()方法中将下载和解压缩文件的过程封装到android内部存储中。 我遇到的问题是,我开发的unZipIntoInternalStorage()方法(粘贴下来),有时会永远运行下去。通常,解压徽标并将其保存到内部存储器大约需要900毫秒的时间,但由于某些未知原因,在循环过程中,大约有4个执行块

我正在开发一个android应用程序,需要从Web服务器下载一个带有少量徽标(平均大小为20-30KB的png文件)的zip文件(最大约1.5MB)

我已经在
AsyncTask
doInbackground()
方法中将下载和解压缩文件的过程封装到android内部存储中。
我遇到的问题是,我开发的
unZipIntoInternalStorage()
方法(粘贴下来),有时会永远运行下去。通常,解压徽标并将其保存到内部存储器大约需要900毫秒的时间,但由于某些未知原因,在循环过程中,大约有4个执行块中的1个执行块(并且“永远”停留在那里,解压所有png文件需要2或3分钟以上):

已编辑:在完成一些日志记录和调试之后,我发现执行速度太慢,执行速度太慢了:
zipInputStream.read(buffer)
在while条件内。你知道为什么有时候它跑得非常快,而有些却非常慢吗

下面是我解压下载文件并将其保存到android内部存储的完整方法。我还添加了从下载的zip文件初始化
zipInputStream
的方法(这两种方法都在
doInBackground()中执行)

为了澄清这一点,在多次测试该方法并进行调试之后,我前面描述的嵌套while循环中始终会发生阻塞。但我找不到原因(见编辑的澄清) 另外,我已经使用
BufferedOutputStream
类尝试了这种方法,结果是相同的:嵌套的while循环有时永远运行,而其他循环在不到一秒钟的时间内成功解压

希望我已经尽可能清楚了,因为我已经花了很长时间在几篇关于解压缩文件或java I/O方法的文章中寻找问题的可能原因,但都没有成功


谢谢你的帮助。谢谢

我怀疑问题出在输入流而不是输出

尝试:
返回新的ZipInputStream(新的BufferedInputStream(urlConnection.getInputStream())

您可以添加一个参数来设置缓冲区大小,但是默认设置应该适合您的用例

该问题通常是由较小的数据包大小引起的,导致一次读取强制执行多个IO操作

理想情况下,您确实希望同时使用BufferedOutputStream,因为
读取
可以读取远小于1kB的数据,但您仍然需要为每次写入支付完整的I/O

作为一般规则,请记住I/O的速度比您可以执行的任何其他操作都慢100倍,并且通常会导致调度程序将您的任务置于等待状态。因此,只要在流不在内存中的任何位置使用BufferedStream(即,基本上总是StringBufferXXXStream除外)


在您的情况下,由于zip协议,当zip解析和解释压缩文件的标题和内容时,
读取
可能会导致实际网络套接字上的任何数量的较小读取

我知道这个错误。如果您的zip文件已损坏,当您尝试通过
ZipInputStream
解压它时,它将是一个无限循环,因为该文件没有EOF

但是如果你用ZipFile解压它,你可以捕捉到这个异常

public static boolean unZipByFilePath(String fileName, String unZipDir) {
    long startUnZipTime = System.currentTimeMillis();
    try {
        File f = new File(unZipDir);
        if (!f.exists()) {
            f.mkdirs();
        }

        BufferedOutputStream dest = null;
        BufferedInputStream is = null;
        ZipEntry entry;
        ZipFile zipfile = new ZipFile(fileName);
        Enumeration e = zipfile.entries();
        while (e.hasMoreElements()) {
            entry = (ZipEntry) e.nextElement();
            is = new BufferedInputStream(zipfile.getInputStream(entry));
            int count = 0;
            byte data[] = new byte[BUFFER];

            String destFilePath = unZipDir + "/" + entry.getName();
            File desFile = new File(destFilePath);
            if (entry.isDirectory()) {
                desFile.mkdirs();
            } else if (!desFile.exists()) {
                desFile.getParentFile().mkdirs();
                desFile.createNewFile();
            }

            FileOutputStream fos = new FileOutputStream(destFilePath);
            dest = new BufferedOutputStream(fos, BUFFER);
            while ((count = is.read(data, 0, BUFFER)) != -1) {
                dest.write(data, 0, count);
            }
            dest.flush();
            dest.close();
            is.close();
        }
        zipfile.close();
    } catch (Exception e) {
        Log.e(TAG, "unZipByFilePath failed : " + e.getMessage());
        return false;
    }
    return true;
}

我相信您遇到了在内部
while
循环中找不到的“流结束”(并且您指出内部while循环似乎是导致问题的原因)。按原样,内部while循环只有在接收到“流结束”时才会退出,但我必须承认,我不知道“流结束”标记是什么,只是我也遇到过类似的问题。那么,如何解决没有找到流结束的问题呢?在这种情况下,是否有任何代码可以中止解压?是否可以记录或打印每次迭代的计数值?这将为您提供一条线索,
read()
方法是否永久阻塞,或者
write()
方法是否永久阻塞。如果
count==0
(根据InputStream的规范,这种情况永远不会发生)可能会发生有趣的问题。在
ZipInputStream
中包装了什么类型的
InputStream
?它是文件输入流还是来自套接字的输入流?在后一种情况下,网络可能会出现问题。而且,由于解压是在一个单独的线程上执行的,您确定解压过程中实际创建
异步任务的线程没有关闭
ZipInputStream
吗?可能
urlConnection.setReadTimeout(ms)需要吗?1 KiB的缓冲区也有点小。我尝试了你的建议,将urlConnection.getInputStream()包装在BufferedOutputStream中,并将FileOutputStream包装在BufferedOutputStream中,但仍然存在执行时间过长的问题。那么可能与网络插座有关吗?我以为zipInputStream返回的那一刻,网络操作就结束了。不管怎样,谢谢你的建议。我相信Zip流在工作时(即,它是一个流)会解码条目,而不是在协同构造时。由于缓冲没有帮助,你正在访问的服务器可能是罪魁祸首,当你从同一个源IP快速访问大量url时,可能会给你低优先级。我认为要进行调试,我应该将从url获取文件内容(完整)与解码分开,例如,通过中间步骤,在打开ZipStream之前复制到ByteArrayOutputStream。然后在执行操作时,您可以诊断哪些文件需要长时间下载,以及您的性能问题是否来自此下载步骤/网络。显然,您是对的!问题似乎来自服务器。在我们在Amazon上使用web服务器(带有nginx服务器的EC2实例)之前,最近我们已经迁移到Amazon cloudfront来为
        private void unZipIntoInternalStorage(ZipInputStream zipInputStream) {
        long start = System.currentTimeMillis();
        Log.i(LOG_TAG, "Unzipping started ");
        try {
            File iconsDir = context.getDir("icons", Context.MODE_PRIVATE);
            ZipEntry zipEntry;
            byte[] buffer = new byte[1024];
            int count;
            FileOutputStream outputStream;

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                File icon = new File(iconsDir, zipEntry.getName());
                outputStream = new FileOutputStream(icon);

                while ((count = zipInputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, count);
                }
                zipInputStream.closeEntry();
                outputStream.close();
            }
            zipInputStream.close();
        } catch (Exception e) {
            Log.e(LOG_TAG + " Decompress", "unzip error ", e);
            e.printStackTrace();
        }
        Log.i(LOG_TAG, "Unzipping completed time required: " + (System.currentTimeMillis() - start) + " ms");
    }

    private ZipInputStream httpDownloadIconsZip(String zipUrl) {

        URLConnection urlConnection;
        try {
            URL finalUrl = new URL(zipUrl);
            urlConnection = finalUrl.openConnection();
            return new ZipInputStream(urlConnection.getInputStream());
        } catch (IOException e) {
            Log.e(LOG_TAG, Log.getStackTraceString(e));
            return null;
        }
    }
public static boolean unZipByFilePath(String fileName, String unZipDir) {
    long startUnZipTime = System.currentTimeMillis();
    try {
        File f = new File(unZipDir);
        if (!f.exists()) {
            f.mkdirs();
        }

        BufferedOutputStream dest = null;
        BufferedInputStream is = null;
        ZipEntry entry;
        ZipFile zipfile = new ZipFile(fileName);
        Enumeration e = zipfile.entries();
        while (e.hasMoreElements()) {
            entry = (ZipEntry) e.nextElement();
            is = new BufferedInputStream(zipfile.getInputStream(entry));
            int count = 0;
            byte data[] = new byte[BUFFER];

            String destFilePath = unZipDir + "/" + entry.getName();
            File desFile = new File(destFilePath);
            if (entry.isDirectory()) {
                desFile.mkdirs();
            } else if (!desFile.exists()) {
                desFile.getParentFile().mkdirs();
                desFile.createNewFile();
            }

            FileOutputStream fos = new FileOutputStream(destFilePath);
            dest = new BufferedOutputStream(fos, BUFFER);
            while ((count = is.read(data, 0, BUFFER)) != -1) {
                dest.write(data, 0, count);
            }
            dest.flush();
            dest.close();
            is.close();
        }
        zipfile.close();
    } catch (Exception e) {
        Log.e(TAG, "unZipByFilePath failed : " + e.getMessage());
        return false;
    }
    return true;
}