如何检查生成的 zip 文件是否已损坏?

发布于 2024-08-18 23:26:05 字数 1186 浏览 5 评论 0原文

我们有一段代码可以在我们的系统上生成一个 zip 文件。一切正常,但有时该 zip 文件在由 FilZip 或 WinZip 打开时被认为已损坏。

所以这是我的问题:我们如何以编程方式检查生成的 zip 文件是否已损坏?

这是我们用来生成 zip 文件的代码:

try {
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpFile));
    byte[] buffer = new byte[16384];
    int contador = -1;
    for (DigitalFile digitalFile : document.getDigitalFiles().getContent()) {
       ZipEntry entry = new ZipEntry(digitalFile.getName());
       FileInputStream fis = new FileInputStream(digitalFile.getFile());
       try {
          zos.putNextEntry(entry);
          while ((counter = fis.read(buffer)) != -1) {
             zos.write(buffer, 0, counter);
          }
          fis.close();
          zos.closeEntry();
       } catch (IOException ex) {
          throw new OurException("It was not possible to read this file " + arquivo.getId());
       }
    }
    try {
      zos.close();
    } catch (IOException ex) {
      throw new OurException("We couldn't close this stream", ex);
    }

我们在这里做错了什么吗?

编辑: 其实上面的代码是完全没问题的。我的问题是我为我的用户重定向了错误的流。因此,他们不是打开 zip 文件,而是打开完全不同的文件。我很抱歉 :(

但主要问题仍然是:如何以编程方式验证给定的 zip 文件是否未损坏?

we have a piece of code which generates a zip file on our system. Everything is ok, but sometimes this zip file while opened by FilZip or WinZip is considered to be corrupted.

So here is my question: how can we check programatically if a generated zip file is corrupted?

Here is the code we are using to generate our zip files:

try {
    ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpFile));
    byte[] buffer = new byte[16384];
    int contador = -1;
    for (DigitalFile digitalFile : document.getDigitalFiles().getContent()) {
       ZipEntry entry = new ZipEntry(digitalFile.getName());
       FileInputStream fis = new FileInputStream(digitalFile.getFile());
       try {
          zos.putNextEntry(entry);
          while ((counter = fis.read(buffer)) != -1) {
             zos.write(buffer, 0, counter);
          }
          fis.close();
          zos.closeEntry();
       } catch (IOException ex) {
          throw new OurException("It was not possible to read this file " + arquivo.getId());
       }
    }
    try {
      zos.close();
    } catch (IOException ex) {
      throw new OurException("We couldn't close this stream", ex);
    }

Is there anything we are doing wrong here?

EDIT:
Actually, the code above is absolutely ok. My problem was that I was redirecting the WRONG stream for my users. So, instead of opening a zip file they where opening something completely different. Mea culpa :(

BUT the main question remains: how programatically I can verify if a given zip file is not corrupted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

独自唱情﹋歌 2024-08-25 23:26:05

您可以使用 ZipFile 类来检查您的文件:

 static boolean isValid(final File file) {
    ZipFile zipfile = null;
    try {
        zipfile = new ZipFile(file);
        return true;
    } catch (IOException e) {
        return false;
    } finally {
        try {
            if (zipfile != null) {
                zipfile.close();
                zipfile = null;
            }
        } catch (IOException e) {
        }
    }
}

You can use the ZipFile class to check your file :

 static boolean isValid(final File file) {
    ZipFile zipfile = null;
    try {
        zipfile = new ZipFile(file);
        return true;
    } catch (IOException e) {
        return false;
    } finally {
        try {
            if (zipfile != null) {
                zipfile.close();
                zipfile = null;
            }
        } catch (IOException e) {
        }
    }
}
又怨 2024-08-25 23:26:05

我知道这个发布已经有一段时间了,我已经使用了你们所有人提供的代码并提出了这个。这对于实际问题非常有效。检查 zip 文件是否损坏

private boolean isValid(File file) {
    ZipFile zipfile = null;
    ZipInputStream zis = null;
    try {
        zipfile = new ZipFile(file);
        zis = new ZipInputStream(new FileInputStream(file));
        ZipEntry ze = zis.getNextEntry();
        if(ze == null) {
            return false;
        }
        while(ze != null) {
            // if it throws an exception fetching any of the following then we know the file is corrupted.
            zipfile.getInputStream(ze);
            ze.getCrc();
            ze.getCompressedSize();
            ze.getName();
            ze = zis.getNextEntry();
        } 
        return true;
    } catch (ZipException e) {
        return false;
    } catch (IOException e) {
        return false;
    } finally {
        try {
            if (zipfile != null) {
                zipfile.close();
                zipfile = null;
            }
        } catch (IOException e) {
            return false;
        } try {
            if (zis != null) {
                zis.close();
                zis = null;
            }
        } catch (IOException e) {
            return false;
        }

    }
}

I know its been a while that this has been posted, I have used the code that all of you provided and came up with this. This is working great for the actual question. Checking if the zip file is corrupted or not

private boolean isValid(File file) {
    ZipFile zipfile = null;
    ZipInputStream zis = null;
    try {
        zipfile = new ZipFile(file);
        zis = new ZipInputStream(new FileInputStream(file));
        ZipEntry ze = zis.getNextEntry();
        if(ze == null) {
            return false;
        }
        while(ze != null) {
            // if it throws an exception fetching any of the following then we know the file is corrupted.
            zipfile.getInputStream(ze);
            ze.getCrc();
            ze.getCompressedSize();
            ze.getName();
            ze = zis.getNextEntry();
        } 
        return true;
    } catch (ZipException e) {
        return false;
    } catch (IOException e) {
        return false;
    } finally {
        try {
            if (zipfile != null) {
                zipfile.close();
                zipfile = null;
            }
        } catch (IOException e) {
            return false;
        } try {
            if (zis != null) {
                zis.close();
                zis = null;
            }
        } catch (IOException e) {
            return false;
        }

    }
}
遥远的绿洲 2024-08-25 23:26:05

我想您会在 zip 文件生成过程中看到相应的异常堆栈跟踪。因此,您可能不想增强异常处理。

I think you'll see correspondent exception stack trace during zip-file generation. So, you probably wan't to enhance your exception handling.

依 靠 2024-08-25 23:26:05

在我的实现中它看起来像这样。也许它可以帮助你:

//[...]

try {
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);

    zos.putNextEntry(new ZipEntry(file.getName()));

    try {
        final byte[] buf = new byte[BUFFER_SIZE];
        while (true) {
            final int len = bis.read(buf);
            if (len == -1) {
                break;
            }
            zos.write(buf, 0, len);
        }
        zos.flush();
        zos.closeEntry();
    } finally {
        try {
            bis.close();
        } catch (IOException e) {
            LOG.debug("Buffered Stream closing failed");
        } finally {
            fis.close();
        }
    }
} catch (IOException e) {
    throw new Exception(e);
}

//[...]
zos.close

in my implementation it looks like that. maybe it helps you:

//[...]

try {
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);

    zos.putNextEntry(new ZipEntry(file.getName()));

    try {
        final byte[] buf = new byte[BUFFER_SIZE];
        while (true) {
            final int len = bis.read(buf);
            if (len == -1) {
                break;
            }
            zos.write(buf, 0, len);
        }
        zos.flush();
        zos.closeEntry();
    } finally {
        try {
            bis.close();
        } catch (IOException e) {
            LOG.debug("Buffered Stream closing failed");
        } finally {
            fis.close();
        }
    }
} catch (IOException e) {
    throw new Exception(e);
}

//[...]
zos.close
鼻尖触碰 2024-08-25 23:26:05

也许交换以下两行?

fis.close();
zos.closeEntry();

我可以想象 closeEntry() 仍然会从流中读取一些数据。

Perhaps swap the following two lines?;

fis.close();
zos.closeEntry();

I can imagine that the closeEntry() will still read some data from the stream.

策马西风 2024-08-25 23:26:05

您的代码基本上没问题,请尝试找出哪个文件导致损坏的 zip 文件。检查 digitalFile.getFile() 是否始终向 FileInputStream 返回有效且可访问的参数。只需在代码中添加一些日志记录,您就会发现问题所在。

Your code is basically OK, try to find out which file is responsible for the corrupted zip file. Check whether digitalFile.getFile() always returns a valid and accessible argument to FileInputStream. Just add a bit logging to your code and you will find out what's wrong.

丢了幸福的猪 2024-08-25 23:26:05
new ZipFile(file) 

再次压缩文件,因此重复工作,这不是您想要的。尽管只检查一个文件,但问题是压缩 n 个文件。

看看这个: http://www.kodejava.org/examples/336.html< /a>

为您的 zip 创建一个校验

CheckedOutputStream checksum = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum));
...

和:当您完成压缩时显示它

System.out.println("Checksum   : " + checksum.getChecksum().getValue());

您必须使用 java 或其他工具执行相同的读取 zip 操作,检查校验和是否匹配。

有关更多信息,请参阅 https://stackoverflow.com/a/10689488/848072

new ZipFile(file) 

compress again the file, so duplicate efforts and that is not what you are looking for. Despite of the fact that only check one file and the question compress n-files.

Take a look to this: http://www.kodejava.org/examples/336.html

Create a checksum for your zip:

CheckedOutputStream checksum = new CheckedOutputStream(fos, new CRC32());
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(checksum));
...

And when you finish the compression show it

System.out.println("Checksum   : " + checksum.getChecksum().getValue());

You must do the same reading the zip with java or others tools checking if checksums match.

see https://stackoverflow.com/a/10689488/848072 for more information

柠栀 2024-08-25 23:26:05

ZipOutputStream 不关闭 底层流。

您需要做的是:

FileOutputStream fos = new FileOutputStream(...);
ZipOutputStream zos = new ZipOutputStream(fos);

然后在结束块中:

zos.close();
fos.flush(); // Can't remember whether this is necessary off the top of my head!
fos.close();

ZipOutputStream does not close the underlying stream.

What you need to do is:

FileOutputStream fos = new FileOutputStream(...);
ZipOutputStream zos = new ZipOutputStream(fos);

Then in your closing block:

zos.close();
fos.flush(); // Can't remember whether this is necessary off the top of my head!
fos.close();
心欲静而疯不止 2024-08-25 23:26:05

我通过使用 try-with-resources 简化了 Nikhil Das Nomula 的代码:

    public static boolean isValidZipFile(File file) {
        try(ZipFile zipfile = new ZipFile(file); 
            ZipInputStream zis = new ZipInputStream(new FileInputStream(file))
        ) {
            ZipEntry ze = zis.getNextEntry();
            if (ze == null) {
                return false;
            }
            while (ze != null) {
                // if it throws an exception fetching any of the following then we know the file is corrupted.
                zipfile.getInputStream(ze);
                ze.getCrc();
                ze.getCompressedSize();
                ze.getName();

                ze = zis.getNextEntry();
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

起初我认为使用 ZipFile 是多余的,但后来我删除了末尾的一个字节存档文件。 ZipEntry 没有显示问题,但 ZipFile 抛出错误 java.util.zip.ZipException:未找到 zip END header

I simplified the code from Nikhil Das Nomula by using try-with-resources:

    public static boolean isValidZipFile(File file) {
        try(ZipFile zipfile = new ZipFile(file); 
            ZipInputStream zis = new ZipInputStream(new FileInputStream(file))
        ) {
            ZipEntry ze = zis.getNextEntry();
            if (ze == null) {
                return false;
            }
            while (ze != null) {
                // if it throws an exception fetching any of the following then we know the file is corrupted.
                zipfile.getInputStream(ze);
                ze.getCrc();
                ze.getCompressedSize();
                ze.getName();

                ze = zis.getNextEntry();
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

At first I thought using ZipFile was redundant, but then I deleted one byte at the end of the archive file. ZipEntry did not show the problem, but ZipFile threw the error java.util.zip.ZipException: zip END header not found.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文