How to read file from ZIP using InputStream?

后端 未结 7 822
旧巷少年郎
旧巷少年郎 2020-11-29 09:11

I must get file content from ZIP archive (only one file, I know its name) using SFTP. The only thing I\'m having is ZIP\'s InputStream. Most examples show how g

相关标签:
7条回答
  • 2020-11-29 09:28

    Unzip archive (zip) with preserving file structure into given directory. Note; this code use deps on "org.apache.commons.io.IOUtils"), but you can replace it by yours custom 'read-stream' code

    public static void unzipDirectory(File archiveFile, File destinationDir) throws IOException
    {
      Path destPath = destinationDir.toPath();
      try (ZipInputStream zis = new ZipInputStream(new FileInputStream(archiveFile)))
      {
        ZipEntry zipEntry;
        while ((zipEntry = zis.getNextEntry()) != null)
        {
          Path resolvedPath = destPath.resolve(zipEntry.getName()).normalize();
          if (!resolvedPath.startsWith(destPath))
          {
            throw new IOException("The requested zip-entry '" + zipEntry.getName() + "' does not belong to the requested destination");
          }
          if (zipEntry.isDirectory())
          {
            Files.createDirectories(resolvedPath);
          } else
          {
            if(!Files.isDirectory(resolvedPath.getParent()))
            {
              Files.createDirectories(resolvedPath.getParent());
            }
            try (FileOutputStream outStream = new FileOutputStream(resolvedPath.toFile()))
            {
              IOUtils.copy(zis, outStream);
            }
          }
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-29 09:33

    Well, I've done this:

     zipStream = new ZipInputStream(channelSftp.get("Port_Increment_201405261400_2251.zip"));
     zipStream.getNextEntry();
    
     sc = new Scanner(zipStream);
     while (sc.hasNextLine()) {
         System.out.println(sc.nextLine());
     }
    

    It helps me to read ZIP's content without writing to another file.

    0 讨论(0)
  • 2020-11-29 09:36

    The ZipInputStream is an InputStream by itself and delivers the contents of each entry after each call to getNextEntry(). Special care must be taken, not to close the stream from which the contents is read, since it is the same as the ZIP stream:

    public void readZipStream(InputStream in) throws IOException {
        ZipInputStream zipIn = new ZipInputStream(in);
        ZipEntry entry;
        while ((entry = zipIn.getNextEntry()) != null) {
            System.out.println(entry.getName());
            readContents(zipIn);
            zipIn.closeEntry();
        }
    }
    
    private void readContents(InputStream contentsIn) throws IOException {
        byte contents[] = new byte[4096];
        int direct;
        while ((direct = contentsIn.read(contents, 0, contents.length)) >= 0) {
            System.out.println("Read " + direct + "bytes content.");
        }
    }
    

    When delegating reading contents to other logic, it can be necessary to wrap the ZipInputStream with a FilterInputStream to close only the entry instead of the whole stream as in:

    public void readZipStream(InputStream in) throws IOException {
        ZipInputStream zipIn = new ZipInputStream(in);
        ZipEntry entry;
        while ((entry = zipIn.getNextEntry()) != null) {
            System.out.println(entry.getName());
    
            readContents(new FilterInputStream(zipIn) {
                @Override
                public void close() throws IOException {
                    zipIn.closeEntry();
                }
            });
        }
    }
    
    0 讨论(0)
  • 2020-11-29 09:37

    Below is a simple example on how to extract a ZIP File, you will need to check if the file is a directory. But this is the simplest.

    The step you are missing is reading the input stream and writing the contents to a buffer which is written to an output stream.

    // Expands the zip file passed as argument 1, into the
    // directory provided in argument 2
    public static void main(String args[]) throws Exception
    {
        if(args.length != 2)
        {
            System.err.println("zipreader zipfile outputdir");
            return;
        }
    
        // create a buffer to improve copy performance later.
        byte[] buffer = new byte[2048];
    
        // open the zip file stream
        InputStream theFile = new FileInputStream(args[0]);
        ZipInputStream stream = new ZipInputStream(theFile);
        String outdir = args[1];
    
        try
        {
    
            // now iterate through each item in the stream. The get next
            // entry call will return a ZipEntry for each file in the
            // stream
            ZipEntry entry;
            while((entry = stream.getNextEntry())!=null)
            {
                String s = String.format("Entry: %s len %d added %TD",
                                entry.getName(), entry.getSize(),
                                new Date(entry.getTime()));
                System.out.println(s);
    
                // Once we get the entry from the stream, the stream is
                // positioned read to read the raw data, and we keep
                // reading until read returns 0 or less.
                String outpath = outdir + "/" + entry.getName();
                FileOutputStream output = null;
                try
                {
                    output = new FileOutputStream(outpath);
                    int len = 0;
                    while ((len = stream.read(buffer)) > 0)
                    {
                        output.write(buffer, 0, len);
                    }
                }
                finally
                {
                    // we must always close the output file
                    if(output!=null) output.close();
                }
            }
        }
        finally
        {
            // we must always close the zip file.
            stream.close();
        }
    }
    

    Code excerpt came from the following site:

    http://www.thecoderscorner.com/team-blog/java-and-jvm/12-reading-a-zip-file-from-java-using-zipinputstream#.U4RAxYamixR

    0 讨论(0)
  • 2020-11-29 09:42

    OP was close. Just need to read the bytes. The call to getNextEntry positions the stream at the beginning of the entry data (docs). If that's the entry we want (or the only entry), then the InputStream is in the right spot. All we need to do is read that entry's decompressed bytes.

    byte[] bytes = new byte[(int) entry.getSize()];
    int i = 0;
    while (i < bytes.length) {
        // .read doesn't always fill the buffer we give it.
        // Keep calling it until we get all the bytes for this entry.
        i += zipStream.read(bytes, i, bytes.length - i);
    }
    

    So if these bytes really are text, then we can decode those bytes to a String. I'm just assuming utf8 encoding.

    new String(bytes, "utf8")
    

    Side note: I personally use apache commons-io IOUtils to cut down on this kind of lower level stuff. The docs for ZipInputStream.read seem to imply that read will stop at the end of the current zip entry. If that is true, then reading the current textual entry is one line with IOUtils.

    String text = IOUtils.toString(zipStream)
    
    0 讨论(0)
  • 2020-11-29 09:51

    If content of your ZIP consist of 1 file (for example, zipped content of HTTP response), you can read text content using Kotlin as follows:

    @Throws(IOException::class)
    fun InputStream.readZippedContent() = ZipInputStream(this).use { stream ->
         stream.nextEntry?.let { stream.bufferedReader().readText() } ?: String()
    }
    

    This extension function unzips first ZIP entry of Zip file and read content as plain text.

    Usage:

    val inputStream: InputStream = ... // your zipped InputStream
    val textContent = inputStream.readZippedContent()
    
    0 讨论(0)
提交回复
热议问题