【问题标题】:java gzip can't keep original file's extension namejava gzip不能保留原始文件的扩展名
【发布时间】:2026-01-26 12:20:06
【问题描述】:

我正在使用 GZIPOutputStream 将一个 xml 文件压缩为 gz 文件,但压缩后我发现 gz 文件层次结构中缺少 xml 文件的扩展名 (.xml)。我需要保留扩展名,因为第三方系统将使用压缩的 gz 文件,该系统期望在解压缩 gz 文件后获得一个 .xml 文件。有什么解决方案吗?我的测试代码是:

public static void main(String[] args) {
    compress("D://test.xml", "D://test.gz");
}

private static boolean compress(String inputFileName, String targetFileName){
     boolean compressResult=true;
     int BUFFER = 1024*4;
     byte[] B_ARRAY = new byte[BUFFER]; 
     FileInputStream fins=null;
     FileOutputStream fout=null;
     GZIPOutputStream zout=null;
     try{
         File srcFile=new File(inputFileName);
         fins=new FileInputStream (srcFile);
         File tatgetFile=new File(targetFileName);
         fout = new FileOutputStream(tatgetFile);
         zout = new GZIPOutputStream(fout);
         int number = 0; 
         while((number = fins.read(B_ARRAY, 0, BUFFER)) != -1){
             zout.write(B_ARRAY, 0, number);  
         }
     }catch(Exception e){
         e.printStackTrace();
         compressResult=false;
     }finally{
         try {
            zout.close();
            fout.close();
            fins.close();
        } catch (IOException e) {
            e.printStackTrace();
            compressResult=false;
        }
     }
     return compressResult;
}

【问题讨论】:

  • GZipOutputStream 不关心文件,它只是压缩你扔给它的字节。您保存该流的文件名应该是您在targetFileName 中设置的任何内容。
  • 是的,运行这段代码后,我们可以得到一个名为“test.gz”的文件,如果我们使用诸如WinRAR之类的zip工具查看这个文件,我们可以看到一个名为作为其中的“测试”(不是“test.xml”);如果我们直接解压“test.gz”,我们会得到一个文件“test”而不是“test.xml”,这就是我提到的问题。
  • 是的,这正是您需要将压缩文件命名为 test.xml.gz 的原因 - 在 Unix/Linux 系统上尝试一下。如果你去掉文件扩展名并用“gz”替换它,你当然会丢失扩展名。

标签: java gzip


【解决方案1】:

不知道问题出在哪里,你在调用你自己的压缩函数

private static boolean compress(String inputFileName, String targetFileName)

使用以下参数

compress("D://test.xml", "D://test.gz");

很明显你会丢失文件名的 .xml 部分,你永远不会将它传递到你的方法中。

【讨论】:

    【解决方案2】:

    也许我遗漏了一些东西,但是当我过去压缩文件时,比如test.xml,我得到的输出将是test.xml.gz。也许如果您将输出文件名更改为test.xml.tz,您仍会保留原始文件扩展名。

    【讨论】:

    • 请看我上面的cmets,你误会了我的意思。无论如何,谢谢。
    • @Eric:如果原始文件是test.xml,则需要调用文件test.xml.gz。文件名不存储在其他任何地方。
    • @Eric - 我认为您确实需要在文件名中保留“xml”。不然怎么把原来的文件扩展名拉起来?
    • 是的,感谢您的澄清。但是我的问题依然存在,我们从第三方系统获取的文件名为“test.gz”(不是test.xml.gz)但是我们解压后可以得到test.xml,换句话说,不管文件名我改变,例如将其更改为“myTest.gz”我仍然可以通过解压缩获得“test.xml”或通过gzip工具查看内容。我想要这个结果。所以即使我将“test.xml.gz”转移到这个方法,在我将文件重命名为“test.gz”后,.xml 仍然会丢失。谢谢。
    • 使用 gzip,您只是压缩文件 (en.wikipedia.org/wiki/Gzip),因此要保留“.xml”,您需要将“.gz”附加到文件名。要保留整个文件名,您必须存档和压缩 (en.wikipedia.org/wiki/List_of_archive_formats)。正如其他发帖人之一所提到的,您可以先 tar 文件,然后使用 gzip。
    【解决方案3】:

    您的代码非常好。将输出文件名设为“D://test.xml.gz”,您错过了文件扩展名 (.xml)。

       Ex: compress("D://test.xml", "D://test.xml.gz");
    

    【讨论】:

      【解决方案4】:

      您还可以在 GZipping 之前使用 ArchiveOutput 流(如 Tar)。

      【讨论】:

      • 如何在JDK中使用API​​实现?
      【解决方案5】:

      将 ZipOutputStream 与 ZipEntry 一起使用,而不是 GZipOutputStream。这样它将保留原始文件扩展名。

      示例代码如下..

      ZipOutputStream zipOutStream = new ZipOutputStream(new FileOutputStream(zipFile));
          FileInputStream inStream = new FileInputStream(file); // Stream to read file
          ZipEntry entry = new ZipEntry(file.getPath()); // Make a ZipEntry
          zipOutStream.putNextEntry(entry); // Store entry
      

      【讨论】:

        【解决方案6】:

        我也遇到了同样的问题,我发现(apache)commons-compress有一个类似的类——GzipCompressorOutputStream,可以配置参数。

                final File compressedFile = new File("test-outer.xml.gz");
                final GzipParameters gzipParameters = new GzipParameters();
                gzipParameters.setFilename("test-inner.xml");
                final GzipCompressorOutputStream gzipOutputStream = new GzipCompressorOutputStream(new FileOutputStream(compressedFile), gzipParameters);
        

        依赖:

                <dependency>
                  <groupId>org.apache.commons</groupId>
                  <artifactId>commons-compress</artifactId>
                  <version>1.8</version>
                </dependency>
        

        【讨论】:

          【解决方案7】:

          我创建了 GZIPOutputStream 的副本并更改了代码以允许“在 gzip”中使用不同的文件名:

          private final byte[] header = {
              (byte) GZIP_MAGIC,                // Magic number (short)
              (byte)(GZIP_MAGIC >> 8),          // Magic number (short)
              Deflater.DEFLATED,                // Compression method (CM)
              8,                                // Flags (FLG)
              0,                                // Modification time MTIME (int)
              0,                                // Modification time MTIME (int)
              0,                                // Modification time MTIME (int)
              0,                                // Modification time MTIME (int)
              0,                                // Extra flags (XFLG)
              0                                 // Operating system (OS)
          };
          
          private void writeHeader() throws IOException {
              out.write(header);
              out.write("myinternalfilename".getBytes());
              out.write(new byte[] {0});
          }
          

          gzip 格式信息:http://www.gzip.org/zlib/rfc-gzip.html#specification

          【讨论】: