如题,zip文件是不是可以附带文本性的注释的呢?
 
另外
我现在需要在项目中实现对多个文件打包成zip下载。从网上找到一段代码如下,可用,但是,会提示getOutputStream已经被called的异常。不知道哪里的问题,请帮忙解决。 
另外这个代码是先保存为文件,然后再向reaponse输出流的,有没有直接压缩后就输出不保存本地文件的方法,请指教。 
另外,如果能够实现一次压缩多个文件夹就更好了。 
帮我解决哪个问题都有分啊。帮忙啊。!!!!package com.xinkao.util;import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.tools.zip.*; 
import javax.servlet.http.HttpServletResponse;public class JspFileDownload {
/** request object */
private HttpServletResponse response = null; /** file type: -1 un-setting; 0 normal file; 1 zip file ;2 stream*/
private int fileType = -1;

/** file name to be displayed */
private String disFileName = null;

/** zip file path */
private String zipFilePath = null;

/** file to be zipped */
private String[] zipFileNames = null;

private boolean zipDelFlag = false;

/** file to be downloaded */
private String downFileName = null;

/** error code 0 */
private static final int PROCESS_OK = 0;

/** error code 1 */
private static final int RESPONSE_IS_NULL = 1;

/** error code 2 */
private static final int UNSET_DOWNLOADTYPE = 2;

/** error code 3 */
private static final int UNSET_DIS_FILE_NAME = 3;

/** error code 4 */
private static final int UNSET_DOWN_FILE_NAME = 4;

/** error code 9 */
private static final int IO_EXCEPTION = 9;

/**
 * set response object
 * @param response response Object
 */
public void setResponse(HttpServletResponse response){
this.response = response;
}

/**
 * set file type 0 normal file; 1 zip file ;2 stream
 * @param fileType
 */
public void setDownType(int fileType){
this.fileType = fileType;
}

/**
 * set display file name
 * @param fileName
 */
public void setDisFileName(String fileName){
this.disFileName = fileName;
}

/**
 * set zip file path
 * @param fileNames
 */
public void setZipFilePath( String path ){
this.zipFilePath = path;
}

public void setZipDelFlag(boolean b){
this.zipDelFlag = b;
}

/**
 * set zip file names
 * @param fileNames
 */
public void setZipFileNames(String[] fileNames){
this.zipFileNames = fileNames;
}

/**
 * set download file name
 * @param fileName
 */
public void setDownFileName(String fileName){
this.downFileName = fileName;
}

/**
 * set file content
 * @param fileContent
 */
public int setFileContent(String fileContent){
try{
byte[] buffs = fileContent.getBytes("GBK");
response.getOutputStream().write(buffs);
}catch(IOException e){
return IO_EXCEPTION;
}
return PROCESS_OK;
}

/**
 * set file content
 * @param fileContent
 */
public int setFileContent(byte[] fileContent){
try{
response.getOutputStream().write(fileContent);
}catch(IOException e){
return IO_EXCEPTION;
}
return PROCESS_OK;
}

/**
 * set file content end
 *
 */
public int setFileContentEnd(){
try{
response.getOutputStream().close();
}catch(IOException e){
return IO_EXCEPTION;
}
return PROCESS_OK;
}

/**
 * main process
 * @return
 */
public int process(){
int status = PROCESS_OK;

status = preCheck();
if ( status != PROCESS_OK )
return status;

String fileName = disFileName;

response.setContentType("APPLICATION/OCTET-STREAM");   
response.setHeader("Content-Disposition","attachment;filename=\"" + fileName + "\"");
int BUFSIZE = 1024 * 8;
int rtnPos = 0;
byte[] buffs = new byte[ BUFSIZE ];
FileInputStream inStream = null;
ZipOutputStream zos = null;
InputStream is = null;
String filepath = null;
try{
  
if ( fileType == 0 || fileType == 1){
if ( fileType == 0 ){
filepath = downFileName;   
}else{
filepath = zipFilePath + fileName;
String[] fileToZip = zipFileNames;
zos=new ZipOutputStream(new FileOutputStream(filepath));
ZipEntry ze=null;
byte[] buf=new byte[BUFSIZE];
int readLen=0;
for (int i= 0;i<fileToZip.length;i++){
File f= new File(fileToZip[i]);

ze=new ZipEntry(f.getName());
ze.setSize(f.length());
ze.setTime(f.lastModified());

zos.putNextEntry(ze);
is=new BufferedInputStream(new FileInputStream(f));
while ((readLen=is.read(buf, 0, BUFSIZE))!=-1) {
zos.write(buf, 0, readLen);
}
is.close();
}
zos.close();
}
   
inStream =new FileInputStream(filepath);   
while((rtnPos=inStream.read(buffs)) >0)   
response.getOutputStream().write(buffs,0,rtnPos);   
response.getOutputStream().close();   
inStream.close();
}
if ( zipDelFlag ){
File fToDel = new File(filepath);
fToDel.delete();
} }catch(IOException e){
return IO_EXCEPTION;
}finally{
try{
if ( inStream != null ){
inStream.close();
inStream = null;
}
if ( zos != null ){
zos.close();
zos = null;
}
if ( is != null ){
is.close();
is = null;
}
}catch (IOException e){
}
}
return status;
}

/**
 * pre check.
 * @return
 */
private int preCheck(){
if ( response == null )
return RESPONSE_IS_NULL;

if ( disFileName == null || disFileName.trim().length() == 0 )
return UNSET_DIS_FILE_NAME;
if ( fileType == -1 )
return UNSET_DOWNLOADTYPE;
else if ( fileType == 0 ){
if ( downFileName == null || downFileName.trim().length() == 0 )
return UNSET_DOWN_FILE_NAME;
else{
if ( !isFile( downFileName ) )
return UNSET_DOWN_FILE_NAME;
}

}else if ( fileType == 1 ){
if ( zipFilePath == null || zipFilePath.length() == 0 )
return UNSET_DOWN_FILE_NAME;
else{
if ( !isDirect(zipFilePath) )
return UNSET_DOWN_FILE_NAME;
}
if ( zipFileNames == null || zipFileNames.length == 0 )
return UNSET_DOWN_FILE_NAME;
else{
for ( int i=0;i<zipFileNames.length;i++ ){
if ( zipFileNames[i] == null || zipFileNames[i].trim().length() == 0 )
return UNSET_DOWN_FILE_NAME;
else{
if ( !isFile( zipFileNames[i] ) )
return UNSET_DOWN_FILE_NAME;
}
}
}
}else if ( fileType == 2 ){
//doing nothing
}else{
return UNSET_DOWNLOADTYPE;
}
return PROCESS_OK;
}

private boolean isFile(String fileName){
File f = new File(fileName);
if (!f.exists() || !f.isFile())
return false;
return true;
}

private boolean isDirect(String filePath){
File f = new File(filePath);
if (!f.exists() || !f.isDirectory())
return false;
return true;
}
}

解决方案 »

  1.   

    现在可以肯定的是zip是可以有和rar文件一样的注释的,详细文件格式如下:
    一个 ZIP 文件由三个部分组成:
            压缩源文件数据区+压缩源文件目录区+压缩源文件目录结束标志
        1、压缩源文件数据区    在这个数据区中每一个压缩的源文件/目录都是一条记录,记录的格式如下:       [文件头+ 文件数据 + 数据描述符]
     
           a、文件头结构         组成                     长度
          文件头标记                  4 bytes  (0x04034b50)
          解压文件所需 pkware 版本    2 bytes
          全局方式位标记              2 bytes
        压缩方式                    2 bytes
        最后修改文件时间             2 bytes
        最后修改文件日期             2 bytes
        CRC-32校验                  4 bytes
        压缩后尺寸                  4 bytes
        未压缩尺寸                  4 bytes
        文件名长度                  2 bytes      扩展记录长度                2 bytes
        文件名                     (不定长度)
        扩展字段                   (不定长度)               b、文件数据                 c、数据描述符    组成     长度
        CRC-32校验                  4 bytes
        压缩后尺寸                   4 bytes
        未压缩尺寸                   4 bytes      这个数据描述符只在全局方式位标记的第3位设为1时才存在(见后详解),紧接在压缩数据的最后一个字节后。这个数据描述符只用在不能对输出的 ZIP 文件进行检索时使用。例如:在一个不能检索的驱动器(如:磁带机上)上的 ZIP 文件中。如果是磁盘上的ZIP文件一般没有这个数据描述符。       2、压缩源文件目录区     在这个数据区中每一条纪录对应在压缩源文件数据区中的一条数据       组成                            长度      目录中文件文件头标记             4 bytes  (0x02014b50)      压缩使用的 pkware 版本          2 bytes      解压文件所需 pkware 版本         2 bytes      全局方式位标记                   2 bytes      压缩方式                        2 bytes      最后修改文件时间                 2 bytes      最后修改文件日期                 2 bytes      CRC-32校验                 4 bytes      压缩后尺寸                      4 bytes      未压缩尺寸                      4 bytes      文件名长度                      2 bytes      扩展字段长度                    2 bytes      文件注释长度                    2 bytes      磁盘开始号                      2 bytes      内部文件属性                    2 bytes      外部文件属性                    4 bytes        局部头部偏移量                  4 bytes      文件名                       (不定长度)      扩展字段                     (不定长度)        文件注释                     (不定长度)      3、压缩源文件目录结束标志        组成                          长度        目录结束标记                    4 bytes  (0x02014b50)        当前磁盘编号                    2 bytes        目录区开始磁盘编号              2 bytes      本磁盘上纪录总数                 2 bytes      目录区中纪录总数                 2 bytes      目录区尺寸大小                   4 bytes      目录区对第一张磁盘的偏移量        4 bytes      ZIP 文件注释长度                 2 bytes      ZIP 文件注释                   (不定长度)