You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何正确读取JarURLInputStream?JAR目录读取为空问题

读取JAR包内目录条目时的流为空问题

尝试读取自身JAR包内容时,使用getResourceAsStream(path)方法获取目录对应的流时,得到的sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream流为空,但读取具体文件时一切正常。

测试代码

package de.CoSoCo.testzone;

import java.io.*;

/**
 *
 * @author Ulf Zibis <Ulf.Zibis@CoSoCo.de>
 * @version 
 */
public class ResourceAsStream {

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    String packagePath = ResourceAsStream.class.getPackageName().replace('.', '/');
    String path;
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    Class c = ResourceAsStream.class;
    InputStream in;
    byte [] bytes = new byte[16];
    try {
      System.out.println("path="+(
          path = packagePath));
      System.out.println("Class="+(
          in = cl.getResourceAsStream(path)));
      BufferedReader r = new BufferedReader(new InputStreamReader(in));
      System.out.println("entries=");
      for (String line; (line = r.readLine()) != null; )
        System.out.println("  "+line);
      in = cl.getResourceAsStream(path);
      System.out.println("read bytes="+in.read(bytes));
    } catch (Exception ex) { System.out.println(ex); }
    try {
      System.out.println("path="+(
          path = packagePath+'/'+"A_Picture.png"));
      System.out.println("Class="+(
          in = cl.getResourceAsStream(path)));
      System.out.println("read bytes="+in.read(bytes));
    } catch (Exception ex) { System.out.println(ex); }
    try {
      System.out.println("path="+(
          path = ""));
      System.out.println("Class="+(
          in = c.getResourceAsStream(path)));
      BufferedReader r = new BufferedReader(new InputStreamReader(in));
      System.out.println("entries=");
      for (String line; (line = r.readLine()) != null; )
        System.out.println("  "+line);
      in = c.getResourceAsStream(path);
      System.out.println("read bytes="+in.read(bytes));
    } catch (Exception ex) { System.out.println(ex); }
    try {
      System.out.println("path="+(
          path = "A_Picture.png"));
      System.out.println("Class="+(
          in = c.getResourceAsStream(path)));
      System.out.println("read bytes="+in.read(bytes));
    } catch (Exception ex) { System.out.println(ex); }
  }
    
}

运行结果

在NetBeans IDE中以独立类文件运行时,能得到预期的目录条目:

path=de/CoSoCo/testzone
Class=java.io.ByteArrayInputStream@4e50df2e
entries=
  A_Picture.png
  ClassFinder.class
  ClassFinder$1.class
  FileChooserDemo.class
  FileTimesFromCalendar.class
  ResourceAsStream.class
read bytes=16
path=de/CoSoCo/testzone/A_Picture.png
Class=java.io.BufferedInputStream@3941a79c
read bytes=16
path=
Class=java.io.ByteArrayInputStream@506e1b77
entries=
  A_Picture.png
  ClassFinder.class
  ClassFinder$1.class
  FileChooserDemo.class
  FileTimesFromCalendar.class
  ResourceAsStream.class
read bytes=16
path=A_Picture.png
Class=java.io.BufferedInputStream@4fca772d
read bytes=16

但从JAR运行时失败:

$ java -jar TestZone.jar
path=de/CoSoCo/testzone
Class=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@3d4eac69
entries=
read bytes=-1
path=de/CoSoCo/testzone/A_Picture.png
Class=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@135fbaa4
read bytes=16
path=
Class=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@330bedb4
entries=
read bytes=-1
path=A_Picture.png
Class=sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@7ea987ac
read bytes=16

原因与解决方案

这不是Java的bug,而是JAR资源的设计特性。当程序在文件系统中运行时,目录是实际存在的文件对象,getResourceAsStream会返回包含目录下文件列表的流;但在JAR包中,目录并非实际的条目(除非JAR中显式包含了目录条目),getResourceAsStream针对目录路径返回的流不包含任何内容。

要读取JAR内的目录条目,正确的做法是通过getResource获取目录的URL,将其转换为JarURLConnection,然后遍历JAR中的所有条目,筛选出目标目录下的内容。示例代码如下:

import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class JarDirectoryReader {
    public static void main(String[] args) throws IOException {
        String packagePath = JarDirectoryReader.class.getPackageName().replace('.', '/') + "/";
        URL url = JarDirectoryReader.class.getClassLoader().getResource(packagePath);
        
        if (url != null && url.getProtocol().equals("jar")) {
            JarURLConnection connection = (JarURLConnection) url.openConnection();
            JarFile jarFile = connection.getJarFile();
            Enumeration<JarEntry> entries = jarFile.entries();
            
            System.out.println("目录下的条目:");
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();
                // 筛选出目标目录下的条目,排除目录本身
                if (entryName.startsWith(packagePath) && !entryName.equals(packagePath)) {
                    // 去掉目录前缀,只显示文件名
                    String fileName = entryName.substring(packagePath.length());
                    // 如果是子目录,这里可以根据需求处理,比如递归遍历
                    if (!entry.isDirectory()) {
                        System.out.println("  " + fileName);
                    }
                }
            }
            jarFile.close();
        }
    }
}

内容的提问来源于stack exchange,提问作者CoSoCo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:05:14