问题描述
我正在尝试将2个文件合并到一个zip文件中
myMainMethod
private void downloadFileByTypeInner(StaticDocument file,String productCode,int productVersion) throws IOException,TechnicalException {
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
HttpServletResponse response = (HttpServletResponse) ec.getResponse();
String distrib = MultinetFrontHelper.getDefaultDitrib();
String realPath = findRealPath(ec,file.getPath().replace("{DISTRIB}",distrib));
String downloadName = file.getDownloadFileName() != null ? file.getDownloadFileName() : file.getPath();
if (file.getAction() == null || file.getAction().trim().isEmpty() || file.getAction().equals("download")) {
List<java.io.File> l = new ArrayList<>();
java.io.File f = new java.io.File(realPath);
l.add(f);
if(file.getDependOnCodeFiles() != null){
String[] paths = file.getDependOnCodeFiles().split(",");
for (String codefile : paths) {
StaticDocument file2 = libraryBusinessService.getFileByCodeType(codefile,productCode,productVersion);
if((file2 != null)) {
l.add(new java.io.File(findRealPath(ec,file2.getPath())));
}
}
downloadName = downloadName.substring(0,downloadName.lastIndexOf("."))+".zip";
}
InputStream pathStream = DownLoadHelper.getStreamAllFiles(l.toArray(new java.io.File[0]),downloadName);
if (pathStream != null) {
if(downloadName.indexOf('/')!=-1) {
downloadName = downloadName.substring(downloadName.lastIndexOf('/')+1);
}
DownLoadHelper.downLoadFile(response,pathStream,downloadName);
} else {
logger.error("Le fichier " + realPath + " est introuvable!");
throw new TechnicalException(CodeError.CODE_ERTEMO0001,null);
}
} else if (file.getAction().equals("open")) {
final FacesContext ctx = FacesContext.getCurrentInstance();
final ExternalContext extContext = ctx.getExternalContext();
try {
extContext.redirect(file.getPath());
} catch (final IOException ioe) {
throw new FacesException(ioe);
}
}
}
getStreamAllFiles
public static InputStream getStreamAllFiles(final File[] listDoc,String nameZIP) throws IOException {
InputStream stream = null;
if (listDoc != null) {
if (listDoc.length == 1) {
stream = new ByteArrayInputStream(FileUtils.readFileToByteArray(listDoc[0]));
} else if (listDoc.length > 1) {
try( ByteArrayOutputStream baos = new ByteArrayOutputStream();ZipOutputStream zos = new ZipOutputStream(baos)){
for (int i = 0; i < listDoc.length; i++) {
try(InputStream fis = new ByteArrayInputStream(FileUtils.readFileToByteArray(listDoc[i]));BufferedInputStream bis = new BufferedInputStream(fis)){
zos.putNextEntry(new ZipEntry(listDoc[i].getName()));
byte[] bytes = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(bytes)) != -1) {
zos.write(bytes,bytesRead);
}
}
}
zos.closeEntry();
stream = new ByteArrayInputStream(baos.toByteArray());
}
}
}
return stream;
}
下载文件
public static void downLoadFile(HttpServletResponse response,InputStream pathStream,String fileName) throws IOException {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition","attachment;filename=" + fileName);
ServletOutputStream out = response.getOutputStream();
IOUtils.copyLarge(pathStream,out);
out.flush();
FacesContext.getCurrentInstance().responseComplete();
IOUtils.closeQuietly(pathStream);
IOUtils.closeQuietly(out);
}
尝试打开zip文件时出现此错误
解决方法
我想您正在尝试使用多个文件制作一个zip文件。问题出在您的getStreamAllFiles
方法中,因为您没有在放置文件内容后关闭zip条目,也没有关闭ZipOutputStream
和循环的结尾,因此文件循环应如下所示:
for (int i = 0; i < listDoc.length; i++) {
try(InputStream fis = new ByteArrayInputStream(FileUtils.readFileToByteArray(listDoc[i]));BufferedInputStream bis = new BufferedInputStream(fis)){
zos.putNextEntry(new ZipEntry(listDoc[i].getName()));
byte[] bytes = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(bytes)) != -1) {
zos.write(bytes,bytesRead);
}
zos.closeEntry();
}
}
zos.close();
stream = new ByteArrayInputStream(baos.toByteArray());
即在文件中循环移动zos.closeEntry()
。
如果不将其移动到listDoc.length
循环中,则如果有多个文件,则在每个条目的末尾将无法正确关闭ZipEntry。您还需要在ZipOutputStream上发出一个close()
,否则它将不会写入zip结束目录(如果在命令行工具下测试该文件,则会显示为错误End-of-central-directory signature not found
)
此外,我将字节缓冲区的分配移到文件循环的外部 ,因为您只需要分配一次,然后对正在编写的所有文件重复使用相同的缓冲区。