java 解压Zip中的PDF压缩中的PDF

67up9zun  于 2023-01-15  发布在  Java
关注(0)|答案(3)|浏览(390)

我已经检查了所有的在线和stackoverflow,找不到特定于此问题的匹配项。我正在尝试提取位于zip文件中的pdf文件,该文件位于zip文件内部(嵌套的压缩)。重新调用我用来提取的方法不起作用,也不改变整个程序接受输入流,而不是我下面这样做。我得到java.io.IOException: Stream Closed。我的代码如下所示,错误行用错误消息指示。

public static void main(String[] args)
    {
        try
        {
            //Paths
            String basePath = "C:\\Users\\user\\Desktop\\Scan\\";
            File lookupDir = new File(basePath + "Data\\");
            String doneFolder = basePath + "DoneUnzipping\\";       
            
            File[] directoryListing = lookupDir.listFiles();
                
            for (int i = 0; i < directoryListing.length; i++) 
            {
                if (directoryListing[i].isFile()) //there's definately a file
                {
                    //Save the current file's path
                    String pathOrigFile = directoryListing[i].getAbsolutePath();
                    Path origFileDone = Paths.get(pathOrigFile);
                    Path newFileDone = Paths.get(doneFolder + directoryListing[i].getName());
                            
                    //unzip it
                    if(directoryListing[i].getName().toUpperCase().endsWith(ZIP_EXTENSION)) //ZIP files
                    {
                        unzip(directoryListing[i].getAbsolutePath(), DESTINATION_DIRECTORY + directoryListing[i].getName());
                            
                        //move to the 'DoneUnzipping' folder
                        Files.move(origFileDone, newFileDone);                            
                        }
                    } 
            }
        } catch (Exception e)
        {
            e.printStackTrace(System.out);
        }
    }
            
    private static void unzip(String zipFilePath, String destDir) 
    {        
        //buffer for read and write data to file
        byte[] buffer = new byte[BUFFER_SIZE];
        
        try {
                FileInputStream fis = new FileInputStream(zipFilePath);
                ZipInputStream zis = new ZipInputStream(fis);
                ZipEntry ze = zis.getNextEntry();
                
                while(ze != null)
                {
                    String fileName = ze.getName();
                    int index = fileName.lastIndexOf("/");
                    String newFileName = fileName.substring(index + 1);
                    File newFile = new File(destDir + File.separator + newFileName);
                    
                    //Zips inside zips  
                    if(fileName.toUpperCase().endsWith(ZIP_EXTENSION))
                    {                      
                        try(ZipInputStream innerZip = new ZipInputStream(fis)) 
                            {
                                ZipEntry innerEntry = null;
                                while((innerEntry = innerZip.getNextEntry()) != null) 
                                {
                                    System.out.println("The file: " + fileName);
                                    if(fileName.toUpperCase().endsWith("PDF")) 
                                    {
                                        FileOutputStream fos = new FileOutputStream(newFile);
                                        int len;
                                        while ((len = zis.read(buffer)) > 0) 
                                        {
                                            fos.write(buffer, 0, len);
                                        }
                                        fos.close();
                                    }
                                }
                            }

                    }
                    
                //close this ZipEntry
                zis.closeEntry(); // java.io.IOException: Stream Closed
                ze = zis.getNextEntry();                       
                
                }  
            
            //close last ZipEntry
            zis.close();
            fis.close();
        } catch (IOException e) 
        {
            e.printStackTrace();
        }
        
    }
busg9geu

busg9geu1#

这个问题的解决方案并不像看起来那么明显,尽管我自己以前写过一些zip实用程序,但从另一个zip文件中获取zip条目只有在回顾时才显得明显
(and第一次尝试时我也得到了java.io.IOException: Stream Closed)。
ZipFileZipInputStream的Java类确实引导您使用文件系统,但这不是必需的。
下面的函数将扫描父级zip文件,并继续扫描,直到找到指定名称的条目。(几乎)所有操作都在内存中完成。
当然,这可以修改为使用不同的搜索条件、查找多个文件类型等,并采取不同的操作,但这至少演示了所讨论的基本技术-- zip文件中的zip文件--不能保证代码的其他方面,更有经验的人很可能会改进这种风格。

final static String ZIP_EXTENSION = ".zip";

public static byte[] getOnePDF() throws IOException
{
    final File source = new File("/path/to/MegaData.zip");
    final String nameToFind = "FindThisFile.pdf";

    final ByteArrayOutputStream mem = new ByteArrayOutputStream();

    try (final ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream(source))))
    {
        digIntoContents(in, nameToFind, mem);
    }

    // Save to disk, if you want
    // copy(new ByteArrayInputStream(mem.toByteArray()), new FileOutputStream(new File("/path/to/output.pdf")));

    // Otherwise, just return the binary data
    return mem.toByteArray();
}

private static void digIntoContents(final ZipInputStream in, final String nameToFind, final ByteArrayOutputStream mem) throws IOException
{
    ZipEntry entry;
    while (null != (entry = in.getNextEntry()))
    {
        final String name = entry.getName();

        // Found the file we are looking for
        if (name.equals(nameToFind))
        {
            copy(in, mem);
            return;
        }

        // Found another zip file
        if (name.toUpperCase().endsWith(ZIP_EXTENSION.toUpperCase()))
        {
            digIntoContents(new ZipInputStream(new ByteArrayInputStream(getZipEntryFromMemory(in))), nameToFind, mem);
        }
    }
}

private static byte[] getZipEntryFromMemory(final ZipInputStream in) throws IOException
{
    final ByteArrayOutputStream mem = new ByteArrayOutputStream();
    copy(in, mem);
    return mem.toByteArray();
}

// General purpose, reusable, utility function
// OK for binary data (bad for non-ASCII text, use Reader/Writer instead)
public static void copy(final InputStream from, final OutputStream to) throws IOException
{
    final int bufferSize = 4096;

    final byte[] buf = new byte[bufferSize];
    int len;
    while (0 < (len = from.read(buf)))
    {
        to.write(buf, 0, len);
    }
    to.flush();
}
qnakjoqk

qnakjoqk2#

导致您的问题的行看起来是您在读取内部zip时创建的自动关闭块:

try(ZipInputStream innerZip = new ZipInputStream(fis)) {
   ...
}

几个可能的问题:首先它读取错误的流fis而不是现有的zis
第二,你不应该在innerZip上使用try-with-resources来自动关闭,因为这会在退出块时隐式调用innerZip.close()。如果你通过一个好的IDE查看ZipInputStream的源代码,你应该看到(最终)ZipInputStream extends InflaterInputStream本身为extends FilterInputStream。调用innerZip.close()将关闭底层外部流zis(在您的情况下为fis)因此,当您恢复外部zip的下一个条目时,流将关闭。
因此,删除try()块并添加zis的使用:

ZipInputStream innerZip = new ZipInputStream(zis);

try-catch块仅用于最外层的文件处理:

try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath))) {
    ZipEntry ze = zis.getNextEntry();
    ...
}

第三,在提取PDF时,您似乎复制了错误的流-使用innerZip而不是外部zis。您应该能够切换到一行Files.copy,简单地如下所示:

if(fileName.toUpperCase().endsWith("PDF")) {
    Files.copy(innerZip, newFile.toPath());
}
yzuktlbb

yzuktlbb3#

你的问题是问如何使用java(在windows中隐含)从一个zip文件中提取一个pdf文件。
在许多系统包括windows中,它是一个单行命令,取决于源文件夹和目标文件夹的位置,然而,使用当前下载文件夹的最短示例,它将在 shell 中,简单如
tar -xf "german (2).zip" && tar -xf "german.zip" && german.pdf
要在windows中解释命令,请参阅How do I execute Windows commands in Java?
默认的pdf查看器可以打开结果,因此Windows Edge或在我的情况下SumatraPDF

一般来说,把pdf文件放在zip文件中是没有意义的,因为它不能在zip文件中运行,所以如果需要下载传输,建议使用单一嵌套。
没有必要为压缩文件添加密码,因为PDF使用自己的密码打开。因此增加两级复杂性是不明智的。保持简单。
如果你有多个zip嵌套在多个zip中,每个zip中有多个pdf,那么你必须通过过滤名称来更具体化,但是尽可能避免额外的洋葱皮。

    • 一米一米一**

您可以通过在内存或临时文件夹中运行来使其复杂化,但是使用本机文件系统是可靠且简单的,因此考虑不使用Java运行它的最快速度

CD /D "C:/Users/user/Desktop/Scan/DoneUnzipping" && for  %f in (..\Data\*.zip) do  tar -xf "%f" "*.zip" && for  %f in (*.zip) do  tar -xf "%f" "*.pdf" && del "*.zip"

这将提取所有内部压缩到工作文件夹,然后提取所有PDF文件,并删除所有必要的临时压缩。源双压缩不会被删除简单地触摸。

相关问题