如何重用/重置ZipInputStream?

时间:2010-10-12 06:35:39

标签: inputstream reset reusability zipinputstream

我想重置ZipInputStream(即返回到起始位置)以便按顺序读取某些文件。我怎么做?我被困了......

      ZipEntry entry;
        ZipInputStream input = new ZipInputStream(fileStream);//item.getInputStream());

        int check =0;
        while(check!=2){

          entry = input.getNextEntry();
          if(entry.getName().toString().equals("newFile.csv")){
              check =1;
              InputStreamReader inputStreamReader = new InputStreamReader(input);
                reader = new CSVReader(inputStreamReader);
                //read files
                //reset ZipInputStream if file is read.
                }
                reader.close();
          }
            if(entry.getName().toString().equals("anotherFile.csv")){
              check =2;
              InputStreamReader inputStreamReader = new InputStreamReader(input);
                reader = new CSVReader(inputStreamReader);
                //read files
                //reset ZipInputStream if file is read.
                }
                reader.close();
          }

        }

5 个答案:

答案 0 :(得分:5)

如果可能(即您有一个实际文件,而不仅仅是要读取的流),请尝试使用ZipFile类而不是更低级别的ZipInputStream。 ZipFile负责在文件中跳转并打开各个条目的流。

ZipFile zip = new ZipFile(filename);
ZipEntry entry = zip.getEntry("newfile.csv");
if (entry != null){
    CSVReader data = new CSVReader(new InputStreamReader(
         zip.getInputStream(entry)));
} 

答案 1 :(得分:2)

实际上无法按预期重置ZipInputStream,因为它不支持重置/标记等。 但是您可以使用ByteArrayOutputStreamInputStream缓存为byte[]

所以你写了一个类似

的类
private byte[] readStreamBuffer;
private InputStream readStream;

public ZipClass(InputStream readStream){
   this.readStream = readStream;
}

openReadStream - 这样的方法:

private ZipInputStream openReadStream(){
    if (readStreamBuffer == null) {
         //If there was no buffered data yet it will do some new
         ByteArrayOutputStream readStreamBufferStream = new ByteArrayOutputStream();
         try {
            int read = 0;
            byte[] buff = new byte[1024];
            while ((read = zipFileInput.read(buff)) != -1) {
               readStreamBufferStream.write(buff, 0, read);
            }
            readStreamBuffer = readStreamBufferStream.toByteArray();
         }
         finally {
            readStreamBufferStream.flush();
            readStreamBufferStream.close();
         }
      }
   //Read from you new buffered stream data
   readStream = new ByteArrayInputStream(readStreamBuffer);

   //open new ZipInputStream
   return new ZipInputStream(readStream);
}

现在您可以阅读条目并在之后关闭它。如果您致电openReadStream,它会为您提供一个新的ZipInputStream,因此您可以选择性地阅读这样的条目:

public InputStream read(String entry){
  ZipInputStream unzipStream = openReadStream();
  try {
     return readZipEntry(unzipStream, entryName);
  }
  finally {
     unzipStream.close(); //This closes the zipinputstream
  }
}

调用方法readZipEntry

private InputStream readZipEntry(ZipInputStream zis, String entry) throws IOException {
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  try {
     // get the zipped file list entry
     try {
        ZipEntry ze = zis.getNextEntry();

        while (ze != null) {
           if (!ze.isDirectory() && ze.getName().equals(entry)) {
              int len;
              byte[] buffer = new byte[BUFFER];
              while ((len = zis.read(buffer)) > 0) {
                 out.write(buffer, 0, len);
              }
              break;
           }
           ze = zis.getNextEntry();
        }
     }
     finally {
        zis.closeEntry();
     }
     InputStream is = new ByteArrayInputStream(out.toByteArray());
     return is;
  }
  finally {
     out.close();
  }
}

你会得到一个新的InputStream。您现在可以从同一输入中多次读取。

答案 2 :(得分:1)

我有同样的问题,我从Blob获取InputStream并且不想使用临时中间文件,因此想要重置ZipInputStream以从ZipInputStream的同一对象再次重新读取ZipEntries,但是我得到了这个另外,它可能对你有帮助。

ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
ZipEntry ze = null;
Map<String, byte[]> fileEntries = new HashMap<String, byte[]>();

while ((ze = zis.getNextEntry()) != null) {

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    int count;

    while ((count = zis.read(buffer)) != -1) {
        baos.write(buffer, 0, count);
    }

    String filename = ze.getName();
    byte[] bytes = baos.toByteArray();                    
    fileEntries.put(filename, bytes);
}
//do what ever with the map of fileEntries

请分享,如果有人有一个好的解决方案,谢谢

答案 3 :(得分:0)

试试这个。它将使用csv处理器处理zip中的每个文件。在我的系统中,输入流是来自HTTP连接的流。

// Get the files inside the zip.
ZipInputStream zin = new ZipInputStream(inputStream);
ZipEntry zentry;
while((zentry = zin.getNextEntry()) != null) {
    String fileName = zentry.getName();
    long fileLength = zentry.getSize();
    System.out.println("fileName:: " + fileName + ", " + fileLength);

    // csv parse it.
    int numLines = 0;
    CSVReader fileReader = new CSVReader(new InputStreamReader(zin));
    String[] nextLine;
    while ( (nextLine = fileReader.readNext()) != null) {
        numLines++;
    }
    zin.closeEntry();

    System.out.println("    number of lines: " + numLines);
}
zin.close();

答案 4 :(得分:0)

您可以将InputStream封装在BufferedInputStream中,并调用方法mark()和reset(),如下所示:

BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
bufferedInputStream.mark(100);
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream);

    any operation with zipInputStream ...

bufferedInputStream.reset();

您传递给mark方法的readLimit必须足够大,以覆盖您对inputStream进行的所有读取操作。如果将其设置为输入中可以假定的最大文件大小,则应包括在内。