【问题标题】:How to extract zip archive with subdirectories using SAF / DocumentFile?如何使用 SAF / DocumentFile 提取带有子目录的 zip 存档?
【发布时间】:2021-02-15 02:31:29
【问题描述】:

您可能知道,我正在努力使用邪恶的存储访问框架提取 zip 文件内容;我不能使用任何 File 对象,所以我必须使用 ZipInputStream、ZipOutputStream 和 DocumentFile,这是 zip 文件结构:

Folder 1/ABC 001.jpg
Folder 1/ABC 002.jpg
Folder 2/ABC 003.jpg
Folder 2/ABC 004.jpg
Folder 2/Folder 3/ABC 005.jpg
Folder 2/Folder 3/ABC 006.jpg
Folder 2/Folder 3/Folder 4/ABC 007.jpg
Folder 2/Folder 3/Folder 4/ABC 008.jpg
ABC 009.jpg

这是我的代码:

    public void extractZipFile(DocumentFile srcZipFile, DocumentFile destDir) throws IOException
    {
        ZipEntry entry;

        InputStream inputStream = resolver.openInputStream(srcZipFile.getUri());

        try (java.util.zip.ZipInputStream zipInputStream = new java.util.zip.ZipInputStream(inputStream))
        {
            while ((entry = zipInputStream.getNextEntry()) != null)
            {
                DocumentFile currentDestDir = destDir;

                if (!entry.isDirectory())
                {
                    unzipFile(entry, zipInputStream, currentDestDir);
                }
                else
                {
                    String finalFolderName = entry.getName().replace("/", "");
                    currentDestDir = destDir.createDirectory(finalFolderName);
                }
            }
        }

        inputStream.close();
    }

    private void unzipFile(ZipEntry fileEntry, java.util.zip.ZipInputStream zipInputStream, DocumentFile destDir) throws IOException
    {
        int readLen;
        byte[] readBuffer = new byte[BUFFER_SIZE];

        DocumentFile destFile = destDir.createFile("*/*", fileEntry.getName());

        try (OutputStream outputStream = resolver.openOutputStream(destFile.getUri()))
        {
            while ((readLen = zipInputStream.read(readBuffer)) != -1)
            {
                outputStream.write(readBuffer, 0, readLen);
            }
        }
    }

这是输出的样子:

谢谢

【问题讨论】:

    标签: java android zipoutputstream zipinputstream saf


    【解决方案1】:

    谢谢大家,我准备好了,我必须构建一个类似下面的方法,它返回 DocumentFile 并创建必要的目录,将其发布在这里以防有人需要...

    private DocumentFile CreateFileWithDirectories(String path, DocumentFile destDir)
    {
        // Like ---> Folder 2/ or Folder 1/Folder 2/Folder 3/
        if (path.endsWith("/"))
        {
            String[] tempStr = path.split("/");
    
            DocumentFile parentDir = destDir;
            DocumentFile childDir = null;
    
            for (String st : tempStr)
            {
                childDir = parentDir.findFile(st);
    
                if (childDir == null)
                {
                    childDir = parentDir.createDirectory(st);
                }
                parentDir = childDir;
            }
    
            // returns null
        }
        // Like ---> 1 Test/Folder 2/Folder 3/ABC 005.jpg
        else if (path.contains("/"))
        {
            String[] tempStr = path.split("/");
    
            DocumentFile parentDir = destDir;
            DocumentFile childDir = null;
    
            for (int i = 0; i < tempStr.length - 1; i++)
            {
                childDir = parentDir.findFile(tempStr[i]);
    
                if (childDir == null) // No file exists
                {
                    childDir = parentDir.createDirectory(tempStr[i]);
                }
    
                //else --> Yes file exists
                parentDir = childDir;
            }
    
            String finalFileName = path.substring(path.lastIndexOf("/") + 1);
    
            return parentDir.createFile("*/*", finalFileName);
        }
        // Like ---> /
        else if (path.equals("/"))
        {
            return null;
        }
        // Like ---> ABC 005.jpg or ABC 005
        else
        {
            return destDir.createFile("*/*", path);
        }
    
        return null;
    }
    

    【讨论】:

    • 也许您可以在使用!zipEntry.isDirectory() 提取时忽略目录并通过循环通过tempStr[0..tempStr.length - 1] 如果documentFile.findFile(tempStr[i]) == null 创建父目录。
    【解决方案2】:

    使用Unzip();方法形式FileUtilsPlus

    【讨论】:

    • 感谢 All Rounder 先生,但该方法使用 ZipFile,它基本上是一个 File 对象,它不适用于 SAF
    【解决方案3】:

    您可以使用SimpleStorage 压缩/解压缩ZIP 文件:

    val zipFile: DocumentFile = ...
    zipFile?.decompressZip(applicationContext, targetFolder, object : ZipDecompressionCallback<DocumentFile>(uiScope) {
        override fun onCompleted(
            zipFile: DocumentFile,
            targetFolder: DocumentFile,
            bytesDecompressed: Long,
            totalFilesDecompressed: Int,
            decompressionRate: Float
        ) {
            Toast.makeText(applicationContext, "Decompressed $totalFilesDecompressed files from ${zipFile.name}", Toast.LENGTH_SHORT).show()
        }
        override fun onFailed(errorCode: ErrorCode) {
            Toast.makeText(applicationContext, "$errorCode", Toast.LENGTH_SHORT).show()
        }
    })
    

    对于压缩文件,可以使用扩展函数List&lt;DocumentFile&gt;.compressToZip()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 2014-04-03
      • 2023-02-09
      相关资源
      最近更新 更多