ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Java 中真正从类路径中读取文本文件

我正在尝试读取在 CLASSPATH 系统变量中设置的文本文件。不是用户变量。

我正在尝试获取文件的输入流,如下所示:

将文件 (D:\myDir) 的目录放在 CLASSPATH 中,然后尝试以下操作:

InputStream in = this.getClass().getClassLoader().getResourceAsStream("SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("/SomeTextFile.txt");
InputStream in = this.getClass().getClassLoader().getResourceAsStream("//SomeTextFile.txt");

将文件 (D:\myDir\SomeTextFile.txt) 的完整路径放在 CLASSPATH 中,然后尝试上面的 3 行代码。

但不幸的是,它们都没有工作,我总是将 null 放入我的 InputStream in


J
Jon Skeet

使用类路径上的目录,从同一个类加载器加载的类中,您应该能够使用以下任一:

// From ClassLoader, all paths are "absolute" already - there's no context
// from which they could be relative. Therefore you don't need a leading slash.
InputStream in = this.getClass().getClassLoader()
                                .getResourceAsStream("SomeTextFile.txt");
// From Class, the path is relative to the package of the class unless
// you include a leading slash, so if you don't want to use the current
// package, include a slash like this:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");

如果这些都不起作用,则表明还有其他问题。

因此,例如,使用以下代码:

package dummy;

import java.io.*;

public class Test
{
    public static void main(String[] args)
    {
        InputStream stream = Test.class.getResourceAsStream("/SomeTextFile.txt");
        System.out.println(stream != null);
        stream = Test.class.getClassLoader().getResourceAsStream("SomeTextFile.txt");
        System.out.println(stream != null);
    }
}

而这个目录结构:

code
    dummy
          Test.class
txt
    SomeTextFile.txt

然后(在 Linux 机器上使用 Unix 路径分隔符):

java -classpath code:txt dummy.Test

结果:

true
true

您混合了相对路径和绝对路径。以“/”开头的路径是绝对路径(即从 CLASSPATH 中列出的任何内容开始)。所有其他路径都相对于您调用 getResourceAsStream() 的类的包
不,你打破了我的榜样。我将编辑注释以使其更清晰,但重点是使用 ClassLoader 所有路径都已假定为绝对路径。他们没有什么可以与之相对的。
也不要使用 Java.IO.File.Separator。它不会在 Windows 上工作。如果您在 Windows 上运行此代码,它仍然必须是 '/' 而不是 '\'
@Pradhan:不,您不应该使用 File.Separator - 因为您不是在请求 file,而是在请求 resource。重要的是要了解所涉及的抽象不是文件系统。
@jagdpanzer:嗯,它只适用于由同一个类加载器加载的类,基本上 - 这是因为 Class.getResourceAsStream 确实是调用 ClassLoader.getResourceAsStream 的便捷方法,但具有“相对”资源的附加功能。如果你指定一个绝对资源,那么任何使用同一个类加载器的调用都会做同样的事情。
y
yawn

使用 Spring 框架(作为实用程序集合容器 - 您不需要使用后一个功能)时,您可以轻松使用 Resource 抽象。

Resource resource = new ClassPathResource("com/example/Foo.class");

通过 Resource 接口,您可以通过 InputStream、URL、URI 或 File 访问资源。将资源类型更改为例如文件系统资源是更改实例的简单问题。


您能否提供一个关于如何在文件 I/O 中使用它的示例代码?我找不到一个体面、明确和直接的方式来说明如何在互联网上使用它:((((
奇迹般有效。提供的一个衬垫就是您所需要的。如果您不知道如何从流中获取字符串,请使用其他示例中的流解析。
我也很难弄清楚如何处理资源变量。我已经更详细地编辑了答案
我已经在使用 Spring 并尝试“纯 Java”方式。 getResource、getResourceAsStream 等之间的差异,没有好的工作示例,这让我很生气。这是一个完美的封装示例,所以我不必在意。
请注意,如果您将项目打包到 jar 中,您应该使用 InputStream。如果您使用 File 它可以在您的 IDE 中工作,但如果您从 jar 中测试它会失败。如果您确实需要文件,请尝试使用 stackoverflow.com/questions/4317035/…
P
Peter Perháč

这就是我使用 Java 7 NIO 在类路径上读取文本文件所有行的方式:

...
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;

...

Files.readAllLines(
    Paths.get(this.getClass().getResource("res.txt").toURI()), Charset.defaultCharset());

注意,这是如何完成的示例。您必须根据需要进行改进。此示例仅在文件实际存在于您的类路径中时才有效,否则当 getResource() 返回 null 并在其上调用 .toURI() 时将引发 NullPointerException。

此外,从 Java 7 开始,指定字符集的一种方便方法是使用 java.nio.charset.StandardCharsets 中定义的常量(根据它们的 javadocs,这些常量“保证在 Java 平台的每个实现上都可用。”)。

因此,如果您知道文件的编码为 UTF-8,则明确指定字符集 StandardCharsets.UTF_8


感谢您提供 NIO 解决方案 - 很少有人使用这个很棒的 API,这是一种耻辱。
读入单个字符串尝试。新字符串(Files.readAllBytes(Paths.get(MyClass.class.getResource(resource).toURI())));
对我来说最好的解决方案,因为它不需要任何依赖项,例如 Spring 或 Commons IO。
如果您的资源文件在 jar 中,例如 maven 模块,这将失败。在这种情况下,您需要使用 SpringStreamUtils.copyToString 之类的东西。
t
tangens

请试试

InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");

您的尝试不起作用,因为只有您的类的类加载器才能从类路径加载。您为 java 系统本身使用了类加载器。


虽然不确定“/”。在这种情况下,相对路径可能会更好。
如果你在没有“/”的情况下使用它,那么你正在“this”的包中寻找你的文件。
InputStream 文件 = this.getClass().getResourceAsStream("SomeTextFile.txt"); InputStream 文件 = this.getClass().getResourceAsStream("/SomeTextFile.txt"); InputStream file = this.getClass().getResourceAsStream("//SomeTextFile.txt");以上都不起作用:(
@Chaitanya:你能从约翰斯基特的回答中运行这个例子吗?
q
qtopierw

要实际读取文件的内容,我喜欢使用 Commons IO + Spring Core。假设 Java 8:

try (InputStream stream = new ClassPathResource("package/resource").getInputStream()) {
    IOUtils.toString(stream);
}

或者:

InputStream stream = null;
try {
    stream = new ClassPathResource("/log4j.xml").getInputStream();
    IOUtils.toString(stream);
} finally {
    IOUtils.closeQuietly(stream);
}

关闭输入流怎么样?
流将自动关闭。它是 Java 7“资源尝试”的一个特性docs.oracle.com/javase/tutorial/essential/exceptions/…
仅当它在 try 语句中时,这里不是这种情况。应该尝试过 (final InputStream stream = new ClassPathResource("/log4j.xml").getInputStream()) {...
5
5agado

要获取类绝对路径,请尝试以下操作:

String url = this.getClass().getResource("").getPath();

然后什么?这些信息本身是没有用的。
这个信息很完美。我只是缺少getPath()!
@Patrick此答案不提供“类绝对路径”。它提供了一个 URL。完全不是一回事。
u
user1695166

不知何故,最好的答案对我不起作用。我需要使用稍微不同的代码。

ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");

我希望这对那些遇到同样问题的人有所帮助。


这对我在 Android 上也有帮助,其中一个类由应用程序加载器加载,但它需要的一个键是在 UI 线程中延迟加载的。
您需要提供有关最佳答案为何不适合您的信息(例如,您的应用程序的结构、您使用的框架、错误等)。最好的答案清楚地表明1)目录需要在类路径上,2)你需要从同一个类加载器加载的类中请求。这些假设之一可能不适用于您的应用程序。上下文类加载器也非常不鼓励,因为它是作为 hack 引入的。某些框架确实使用了它,但了解其含义很重要(这需要您描述项目的背景)
这适用于静态上下文(与此处提到的其他解决方案不同)。
A
Alexey Simonov

如果你使用番石榴:

import com.google.common.io.Resources;

我们可以从 CLASSPATH 中获取 URL:

URL resource = Resources.getResource("test.txt");
String file = resource.getFile();   // get file path 

或输入流:

InputStream is = Resources.getResource("test.txt").openStream();

Ways to convert an InputStream to a String


如果资源在 JAR 或 WAR 文件中,则文件路径没有任何用处。
URL 的 getFile 方法不返回文件名。它只返回 URL 的路径部分,不能保证是有效的文件名。 (URL 类是 Java 1.0 的一部分;当时,大多数 URL 实际上确实引用了同一台计算机或不同计算机上的物理文件。)
我需要检索存储在 recources 下的子图中的图像。使用我的相对文件路径在本地工作,但 Resources.getResource("submap/file").openStream() 是我在远程服务器上部署时得到的唯一解决方案
B
BullyWiiPlaza

要将文件的内容从 classpath 读入字符串,您可以使用以下命令:

private String resourceToString(String filePath) throws IOException, URISyntaxException
{
    try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
    {
        return IOUtils.toString(inputStream);
    }
}

注意:
IOUtilsCommons IO 的一部分。

像这样称呼它:

String fileContents = resourceToString("ImOnTheClasspath.txt");

A
Aaron Digulla

您说“我正在尝试读取在 CLASSPATH 系统变量中设置的文本文件。”我猜这是在 Windows 上,您正在使用这个丑陋的对话框来编辑“系统变量”。

现在您在控制台中运行您的 Java 程序。这不起作用:控制台在启动时会获取系统变量值的副本。这意味着之后对话框中的任何更改都不会产生任何影响。

有这些解决方案:

每次更改后启动一个新控制台 在控制台中使用 set CLASSPATH=... 在控制台中设置变量的副本,当您的代码工作时,将最后一个值粘贴到变量对话框中。将对 Java 的调用放入 .BAT 文件并双击它。这将每次创建一个新控制台(从而复制系统变量的当前值)。

注意:如果您还有一个用户变量 CLASSPATH,那么它会影响您的系统变量。这就是为什么最好将 Java 程序的调用放入 .BAT 文件并在其中设置类路径(使用 set CLASSPATH=)而不是依赖全局系统或用户变量。

这也确保您可以在您的计算机上运行多个 Java 程序,因为它们必然具有不同的类路径。


A
Abhijit Pritam Dutta

我的回答与问题中所问的不完全一样。相反,我给出了一个解决方案,我们可以多么容易地从我们的项目类路径中将文件读入 Java 应用程序。

例如,假设配置文件名 example.xml 位于如下路径中:-

com.myproject.config.dev

我们的 java 可执行类文件位于以下路径中:-

com.myproject.server.main

现在只需检查上述路径,这是最近的公共目录/文件夹,您可以从中访问 dev 和主目录/文件夹(com.myproject.server.main - 我们的应用程序的 java 可执行类所在的位置) - 我们可以看到它是 myproject 文件夹/目录,它是我们可以访问 example.xml 文件的最近的公共目录/文件夹。因此,从位于文件夹/目录 main 中的 java 可执行类中,我们必须返回两个步骤,如 ../../ 来访问 myproject。现在按照这个,看看我们如何读取文件:-

package com.myproject.server.main;

class Example {

  File xmlFile;

  public Example(){
       String filePath = this.getClass().getResource("../../config/dev/example.xml").getPath();
       this.xmlFile = new File(filePath);
    }

  public File getXMLFile() {
      return this.xmlFile;
  }
   public static void main(String args[]){
      Example ex = new Example();
      File xmlFile = ex.getXMLFile();
   }
}

谢谢,在 api 不提供流参数的情况下很有用。
B
Boendal

如果您在 jar 文件中编译您的项目:您可以将文件放在 resources/files/your_file.text 或 pdf 中;

并使用此代码:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;

public class readFileService(){
    private static final Logger LOGGER = LoggerFactory.getLogger(readFileService.class);


    public byte[] getFile(){
        String filePath="/files/your_file";
        InputStream inputStreamFile;
        byte[] bytes;
        try{
            inputStreamFile = this.getClass().getResourceAsStream(filePath);
            bytes = new byte[inputStreamFile.available()];
            inputStreamFile.read(bytes);    
        } catch(NullPointerException | IOException e) {
            LOGGER.error("Erreur read file "+filePath+" error message :" +e.getMessage());
            return null;
        }
        return bytes;
    } 
}

n
ndnenkov

我正在使用 webshpere 应用程序服务器,我的 Web 模块是基于 Spring MVC 构建的。 Test.properties 位于资源文件夹中,我尝试使用以下内容加载此文件:

this.getClass().getClassLoader().getResourceAsStream("Test.properties"); this.getClass().getResourceAsStream("/Test.properties");

上述代码均未加载文件。

但在以下代码的帮助下,属性文件已成功加载:

Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");

感谢用户“user1695166”。


欢迎来到堆栈溢出!请不要添加“谢谢”作为答案,即使您还部分地提供了您的解决方案是如何进行的,如果您的解决方案与另一个帖子相同,则不需要添加。在网站上投入一些时间后,您将获得足够的 privileges 来支持您喜欢的答案,这是 Stack Overflow 表达感谢的方式。
C
Charu Khurana

使用org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));


不应使用对 src 的引用...在最终工件中不起作用。
s
sachinthana87

不要使用 getClassLoader() 方法并在文件名前使用“/”。 “/“ 非常重要

this.getClass().getResourceAsStream("/SomeTextFile.txt");

使用前导 / 与使用 getClassLoader() 方法的效果完全相同。
J
Janny
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class ReadFile

{
    /**
     * * feel free to make any modification I have have been here so I feel you
     * * * @param args * @throws InterruptedException
     */

    public static void main(String[] args) throws InterruptedException {
        // thread pool of 10
        File dir = new File(".");
        // read file from same directory as source //
        if (dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {
                // if you wanna read file name with txt files
                if (file.getName().contains("txt")) {
                    System.out.println(file.getName());
                }

                // if you want to open text file and read each line then
                if (file.getName().contains("txt")) {
                    try {
                        // FileReader reads text files in the default encoding.
                        FileReader fileReader = new FileReader(
                                file.getAbsolutePath());
                        // Always wrap FileReader in BufferedReader.
                        BufferedReader bufferedReader = new BufferedReader(
                                fileReader);
                        String line;
                        // get file details and get info you need.
                        while ((line = bufferedReader.readLine()) != null) {
                            System.out.println(line);
                            // here you can say...
                            // System.out.println(line.substring(0, 10)); this
                            // prints from 0 to 10 indext
                        }
                    } catch (FileNotFoundException ex) {
                        System.out.println("Unable to open file '"
                                + file.getName() + "'");
                    } catch (IOException ex) {
                        System.out.println("Error reading file '"
                                + file.getName() + "'");
                        // Or we could just do this:
                        ex.printStackTrace();
                    }
                }
            }
        }

    }

}

不以任何方式回答问题。
S
Salandur

你必须把你的“系统变量”放在java类路径上。


我把系统变量本身。
“系统变量”是 Java CLASSPATH。回答没有意义。
完全正确......甚至不记得写过这个答案:)