• 使用commons-compress解压GBK格式winzip文件到UTF8,以及错误使用ZipArchiveInputStream读出来数据全是空的解决办法


      先上正确方法:

      正确方式应该为,先创建一个ZipFile,然后对其entries做遍历,每一个entry其实就是一个文件或者文件夹,检测到文件夹的时候创建文件夹,其他情况创建文件,其中使用zipFile.getInputStream(entry)可以获得当前文件的输入流(注意是文件的输入流不是压缩文件的输入流)。然后把它写到writer里就可以了。嘛,明明很简单的。下面是一个例子,读取GBK格式的压缩包,压缩包中的文件编码也为GBK格式(就是在windows下写的文件并打包的情况),输出为UTF8的解压(跨平台使用)。

      def decompressZip(source: File, dest: String, sourceCharacters: String = "GBK", destCharacters: String = "UTF-8") = {
          if (source.exists) {
              var os: OutputStream = null
              var inputStream: InputStreamReader = null
              var outWriter: OutputStreamWriter = null
                val zipFile = new ZipFile(source, sourceCharacters)
                var entries = zipFile.getEntries
                
                entries.foreach(entry =>
                    if (entry.isDirectory())
                        new File(dest + entry.getName).mkdirs()                    
                    else if (entry != null) {
                      try{
                          val name = entry.getName
                          val path = dest + name
                          var content = new Array[Char](entry.getSize.toInt)                      
                          inputStream = new InputStreamReader(zipFile.getInputStream(entry), sourceCharacters)
                          println(inputStream.read(content))
                  val entryFile = new File(path)
                          checkFileParent(entryFile)
                  os = new FileOutputStream(entryFile)
                          outWriter = new OutputStreamWriter(os, destCharacters);
                          outWriter.write(new String(content))
                      } catch {
                          case e: Throwable => e.printStackTrace()
                      }finally{
                            if (os != null){
                                os.flush
                                os.close
                            }
                            if (outWriter != null){
                                outWriter.flush
                                outWriter.close
                            }
                            if (inputStream != null) inputStream.close
                        }
                  })
              zipFile.close
          }
      }

      错误示范:

      不知道为什么,网上很多教程都是使用ZipArchiveInputStream来进行解压,然而:

      The ZipFile class is preferred when reading from files as ZipArchiveInputStream is limited by not being able to read the central directory header before returning entries. In particular ZipArchiveInputStream

    • may return entries that are not part of the central directory at all and shouldn't be considered part of the archive.
    • may return several entries with the same name.
    • will not return internal or external attributes.
    • may return incomplete extra field data.
    • may return unknown sizes and CRC values for entries until the next entry has been reached if the archive uses the data descriptor feature.

      在commons-compress的1.3版本就开始建议使用ZipFile了。

      我个人而言,尝试过ZipArchiveInputStream之后发现一个问题,ZipArchiveInputStream创建方式很麻烦,需要指定一个InputStream,而这个方法在API文档中是这么写的

    Constructors
    Constructor and Description
    ZipArchiveInputStream(InputStream inputStream)
    Create an instance using UTF-8 encoding
    ZipArchiveInputStream(InputStream inputStream, String encoding)
    Create an instance using the specified encoding
    ZipArchiveInputStream(InputStream inputStream, String encoding, boolean useUnicodeExtraFields)
    Create an instance using the specified encoding
    ZipArchiveInputStream(InputStream inputStream, String encoding, boolean useUnicodeExtraFields, boolean allowStoredEntriesWithDataDescriptor)
    Create an instance using the specified encoding

      Parameters:inputStream - the stream to wrap

      这个构造方法没有指明这个inputStream参数是什么东西,照网上的方法试了试,使用:  

    val zipFile = new ZipFile(source, sourceCharacters)
    var entries = zipFile.getEntries
    entries.foreach(entry =>
        if (entry != null) {
            try{
                val name = entry.getName
                val path = dest + name
                var content = new Array[Char](entry.getSize.toInt)
                zais = new ZipArchiveInputStream(zipFile.getInputStream(entry))
                val entryFile = new File(path)
            checkFileParent(entryFile)
                   os = new FileOutputStream(entryFile)  
                IOUtils.copy(zais, os)
    ………………

      读出来的数据是空,使用zais.read读出Array[Byte]并把它转化为字符串发现是空白符字符串,直接输出Array[Byte]发现都是0。后来看文档大概知道是什么原因,这个ZipArchiveInputStream读取的应该是Zip文件,然而zipFile.geiInputStream返回的是解压完的文件的输入流,所以才会出现这个问题,试了试commons-compress spark依赖12年出的1.4版本和最新的1.14版本这种方法都是错的,所以我怀疑他们12年之后转的那些博客并没有经过自己使用和测试就转发了。这个ZipFile和ZipArchiveInputStream混用总觉得怪怪的。。。

  • 相关阅读:
    第二章 用电信号传输TCP/IP数据协议栈和网卡
    skiplist.h/filter_policy.h/arena.h/coding.h分析
    slice.h/hash.h/chche.h分析
    comparator.c/log_read.h/block.h/table.h/table_cache.h分析
    sst文件结构/table_builder.h分析
    db_impl.cc Memtable落盘分析和SST文件合并
    postman连接mysql数据库
    postman连接mysql数据库
    MYSQL跨服务器数据表使用
    mysql拼接json数据
  • 原文地址:https://www.cnblogs.com/gaoze/p/7610492.html
Copyright © 2020-2023  润新知