How to reuse / reset an ZipInputStream?

时间秒杀一切 提交于 2019-12-10 16:12:17

问题


I want to reset the ZipInputStream (ie back to the start position) in order to read certain files in order. How do I do that? I am so stucked...

      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();
          }

        }

回答1:


If possible (i.e. you have an actual file, not just a stream to read from), try to use the ZipFile class rather than the more low-level ZipInputStream. ZipFile takes care of jumping around in the file and opening streams to individual entries.

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



回答2:


Actually there is no way to reset a ZipInputStream as you expect, because it does not support reset/markers etc. But you can use an ByteArrayOutputStream to buffer your InputStream as byte[]

so you write a Class looking like

private byte[] readStreamBuffer;
private InputStream readStream;

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

and a openReadStream-method like this:

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);
}

Now you are able to read an entry and close it afterwards. If you call openReadStream it will provide you a new ZipInputStream, so you can selectively read Entries like this:

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

calling the method 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();
  }
}

And you will get out a new InputStream. You can now read multiple times from the same Input.




回答3:


I have the same problem, i am getting InputStream from Blob and don't want to use temporary intermediary files so want to reset the ZipInputStream to re-read the ZipEntries again from the same object of ZipInputStream, But I got this by anotherway, it might help u.

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

please share if any one has a good solution, thanks




回答4:


Try this. It will process each file in the zip using a csv processor. In my system, the input stream is a stream from an HTTP connection.

// 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();



回答5:


You can wrap the InputStream in a BufferedInputStream and call the methods mark() and reset(), like so:

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

    any operation with zipInputStream ...

bufferedInputStream.reset();

The readLimit you pass to the mark method must be big enough to cover all the read operations you do with the inputStream. If you set it to the maximum supposed file size you can have in input you should be covered.



来源:https://stackoverflow.com/questions/3912172/how-to-reuse-reset-an-zipinputstream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!