简体   繁体   English

从 JAR 文件中读取目录内容

[英]Reading Directory Contents From a JAR file

I am trying to write a code in a webapp, where I have a JAR file in my classpath.我正在尝试在 webapp 中编写代码,我的类路径中有一个 JAR 文件。 The objective is to check if the directory exists in the JAR.目的是检查该目录是否存在于 JAR 中。 If yes, I need to save the all the contents of the files inside the JAR's directory in a HashMap<String, String> .如果是,我需要将 JAR 目录中文件的所有内容保存在HashMap<String, String> The Key being the file name and the value being the contents of each file. Key 是文件名,value 是每个文件的内容。

File directory = new File(getClass().getClassLoader().getResource(directoryPath).getPath());

System.out.println("PATH IS: " + directory.getPath());

// Check if  dirPth exists and is a valid directory
if (!directory.isDirectory()) {
    throw new AccessException("Directory \"" + directoryPath + "\" not valid");
}

// Obtain a list of all files under the dirPath
File [] fileList = directory.listFiles();

for (File file : fileList) {

    if (file.isFile()) {

        // Read the file
        BufferedReader br = new BufferedReader(new FileReader(file));
        String line = null;
        StringBuilder sb = new StringBuilder();

        while ((line = br.readLine()) != null) {
            sb.append(line);
        }

        br.close();

        // Store the file data in the hash
        entry.put(file.getName(), sb.toString);
    }
}

The output of the direcotry.getPath() is: direcotry.getPath()的输出是:

file:\\H:\\apache-tomcat-9.0.27\\lib\\myConfigurationFiles.jar!\\META-INF\\Maintenance\\xmlFiles\\secondary文件:\\H:\\apache-tomcat-9.0.27\\lib\\myConfigurationFiles.jar!\\META-INF\\Maintenance\\xmlFiles\\secondary

which is the right folder I am looking for.这是我正在寻找的正确文件夹。

Here the Map object is the "entry".这里的 Map 对象是“条目”。

Now I am not sure why direcotry.isDirectory() returns false.现在我不确定为什么 direcotry.isDirectory() 返回 false。 Shouldn't it return true?它不应该返回true吗?

Now since its not crossing the first exception.现在因为它没有跨越第一个例外。 I have no idea how it will behave after that.我不知道在那之后它会如何表现。 Any help would be appreciated.任何帮助,将不胜感激。

  1. getClass() is the wrong approach for jobs like this; getClass()对于这样的工作是错误的方法; it breaks if anybody subclasses.如果有人子类,它会中断。 The proper way is to use MyClassName.class instead.正确的方法是改用MyClassName.class

  2. getClassLoader().getResource() is also the wrong approach; getClassLoader().getResource()也是错误的做法; this breaks in exotic but possible cases where getClassLoader() returns null.这在getClassLoader()返回 null 的奇特但可能的情况下中断。 Just use getResource and slightly change the path (add a leading slash, or, write the path relative to your class file).只需使用getResource并稍微更改路径(添加前导斜杠,或者写入相对于您的类文件的路径)。

  3. You're turning the string file:\\H:\\apache-tomcat-9.0.27\\lib\\myConfigurationFiles.jar!\\META-INF\\Maintenance\\xmlFiles\\secondary into a filename and then asking if it is a directory.您将字符串file:\\H:\\apache-tomcat-9.0.27\\lib\\myConfigurationFiles.jar!\\META-INF\\Maintenance\\xmlFiles\\secondary转换为文件名,然后询问它是否是目录。 Of course it isn't;当然不是; that isn't even a file.那甚至不是一个文件。 You need to do some string manipulation to extract the actual file out of it: You want just H:\\apache-tomcat-9.0.27\\lib\\myConfigurationFiles.jar , feed that to the java.nio.file API, and then use that to ask if it is a file (it will never be a directory; jars are not directories).您需要进行一些字符串操作以从中提取实际文件:您只需要H:\\apache-tomcat-9.0.27\\lib\\myConfigurationFiles.jar ,将其提供给java.nio.file API,然后使用询问它是否是一个文件(它永远不会是一个目录;jar 不是目录)。

  4. Note that this will not work if the resource you're reading from isn't a jar.请注意,如果您正在读取的资源不是 jar,这将不起作用。 Note that the class loading API is abstracted: You could find yourself in the scenario where source files are generated from scratch or loaded out of a DB, with more exotic URLs being produced by the getResource method to boot.请注意,类加载 API 是抽象的:您可能会发现自己处于从头开始生成源文件或从数据库加载的场景中, getResource方法生成更多奇特的 URL 以进行引导。 Thus, this kind of code simply won't work then.因此,这种代码根本就行不通。 Make sure that's okay first.首先确保没问题。

Thus:因此:

String urlAsString = MyClassName.class.getResource("MyClassName.class").toString(); // produces a link to yourself.

int start = urlAsString.startsWith("file:jar:") ? 8 : urlAsString.startsWith("file:") ? 4 : 0;
int end = urlAsString.lastIndexOf('!');
String jarFileLoc = urlAsString.substring(start, end);

if you want this to apply to actual directories (class files and such can come from dirs instead of files), you could do:如果您希望这适用于实际目录(类文件等可以来自目录而不是文件),您可以执行以下操作:

var map = new HashMap<String, String>();

Path root = Paths.get(jarFileLoc);

Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
        map.put(root.relativize(file), content);
    }
});

for a jar, which is really just a zip, it'll be more like:对于一个 jar,它实际上只是一个 zip,它更像是:

var map = new HashMap<String, String>();
Path root = Paths.get(jarFileLoc);
try (var fileIn = Files.newInputStream(root)) {
    ZipInputStream zip = new ZipInputStream(fileIn);
    for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
        String content = new String(zip.readAllBytes(), StandardCharsets.UTF_8);
        map.put(entry.getName(), content);
    }
}

Make sure you know what charsets are and that UTF_8 is correct here.确保您知道字符集是什么并且 UTF_8 在这里是正确的。

Given a java.nio.file.Path to the jar you want to search ( jarPath ), and a String for the absolute directory name within the jar ( directory ), this may work for you:给定要搜索的 jar ( jarPath ) 的java.nio.file.Path和 jar ( directory ) 中绝对目录名称的String ,这可能对您jarPath

Map<String, String> map = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(jarPath, null)) {
    Path dir = fs.getPath(directory);
    if (Files.exists(dir)) {
        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException {
                map.put(file.toString(), Files.readString(file));
                return super.visitFile(file, attrs);
            }
        });
    }
}

Files.readString is available with Java 11+. Files.readString可用于 Java 11+。 For earlier versions, use:对于早期版本,请使用:

new String(Files.readAllBytes(file), StandardCharsets.UTF_8)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM