如何在 Java 中真正从类路径中读取文本文件
Posted
技术标签:
【中文标题】如何在 Java 中真正从类路径中读取文本文件【英文标题】:How to really read text file from classpath in Java 【发布时间】:2010-11-30 15:51:32 【问题描述】:我正在尝试读取在 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
。
【问题讨论】:
【参考方案1】:使用类路径上的目录,从同一个类加载器加载的类中,您应该能够使用以下任一:
// 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()
的类的包
不,你打破了我的榜样。我将编辑 cmets 以使其更清晰,但重点是使用 ClassLoader 所有路径都已假定为绝对路径。没有什么可以与之相关的。
也不要使用 Java.IO.File.Separator。它不会在 Windows 上工作。如果您在 Windows 上运行此代码,它仍然必须是 '/' 而不是 '\'
@Pradhan:不,你不应该使用File.Separator
- 因为你不是在请求文件,而是在请求资源。重要的是要了解所涉及的抽象不是文件系统。
@jagdpanzer: 嗯,它只适用于由同一个类加载器加载的类,基本上 - 这是因为Class.getResourceAsStream
确实是调用ClassLoader.getResourceAsStream
的便捷方法,但具有“相对”的资源。如果你指定一个绝对资源,那么任何使用同一个类加载器的调用都会做同样的事情。【参考方案2】:
当使用Spring 框架(作为实用程序集合或容器 - 您不需要使用后一个功能)时,您可以轻松地使用资源抽象。
Resource resource = new ClassPathResource("com/example/Foo.class");
通过 Resource 接口,您可以通过 InputStream、URL、URI 或 访问资源文件。将资源类型更改为例如文件系统资源只需更改实例即可。
【讨论】:
您能否提供一个示例代码,说明如何在文件 I/O 中使用它?我找不到关于如何在互联网上使用它的体面、显式和直截了当的方法:(((( 像魅力一样工作。提供的一个衬垫就是您所需要的。如果您不知道如何从流中获取字符串,请使用其他示例中的流解析。 我在弄清楚如何处理资源变量时也遇到了一些麻烦。我已经更详细地编辑了答案 我已经在使用 Spring 并尝试“纯 java”方式。 getResource、getResourceAsStream 等之间的差异,没有好的工作示例,这让我很生气。这是一个完美的封装示例,所以我不必在意。 请注意,如果您将项目打包到 jar 中,您应该使用 InputStream。如果您使用 File 它可以在您的 IDE 中工作,但如果您从 jar 中测试它会失败。如果你真的需要一个文件试试***.com/questions/4317035/…【参考方案3】:这就是我使用 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模块。在这种情况下,您需要使用类似Spring
的StreamUtils.copyToString
。【参考方案4】:
请尝试
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
您的尝试不起作用,因为只有 您的 类的类加载器能够从类路径加载。您为 java 系统本身使用了类加载器。
【讨论】:
不确定“/”。在这种情况下,相对路径可能会更好。 如果你在没有“/”的情况下使用它,你正在“this”的包中寻找你的文件。 InputStream 文件 = this.getClass().getResourceAsStream("SomeTextFile.txt"); InputStream file = this.getClass().getResourceAsStream("/SomeTextFile.txt"); InputStream file = this.getClass().getResourceAsStream("//SomeTextFile.txt");以上都不起作用:( @Chaitanya:你能运行 John Skeet 的回答中的例子吗? 这里有几个good examples for getResourceAsStream【参考方案5】:要真正读取文件的内容,我喜欢使用 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()) ...【参考方案6】:要获得类的绝对路径,试试这个:
String url = this.getClass().getResource("").getPath();
【讨论】:
然后呢?这些信息本身没有用。 这个信息很完美。我只是缺少 getPath()! @Patrick 这个答案不提供“类绝对路径”。它提供了一个 URL。完全不是一回事。【参考方案7】:不知何故,最佳答案对我不起作用。我需要使用稍微不同的代码。
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("SomeTextFile.txt");
我希望这对遇到同样问题的人有所帮助。
【讨论】:
这对我在 android 上的应用程序加载器加载类的情况也有帮助,但它需要的键是在 UI 线程中延迟加载的。 您需要提供有关最佳答案为何不适合您的信息(例如,您的应用程序的结构、您使用的框架、错误等)。最好的答案清楚地表明1)目录需要在类路径上,2)你需要从同一个类加载器加载的类中请求。这些假设之一可能不适用于您的应用程序。上下文类加载器也非常不鼓励,因为它是作为 hack 引入的。一些框架确实使用了它,但了解其含义很重要(这需要您描述项目的背景) 这适用于静态上下文(与此处提到的其他解决方案不同)。【参考方案8】:如果你使用番石榴:
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()
是我在远程服务器上部署时唯一的解决方案【参考方案9】:
要将文件的内容从classpath
读入字符串,您可以使用:
private String resourceToString(String filePath) throws IOException, URISyntaxException
try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(filePath))
return IOUtils.toString(inputStream);
注意:IOUtils
是Commons IO
的一部分。
这样称呼它:
String fileContents = resourceToString("ImOnTheClasspath.txt");
【讨论】:
【参考方案10】:您说“我正在尝试读取在 CLASSPATH 系统变量中设置的文本文件。”我猜这是在 Windows 上,您正在使用这个丑陋的对话框来编辑“系统变量”。
现在您在控制台中运行您的 Java 程序。这不起作用:控制台在启动时会一次获取系统变量值的副本。这意味着对话框中的任何更改之后都不会产生任何影响。
有以下解决方案:
每次更改后启动一个新控制台
在控制台中使用set CLASSPATH=...
在控制台中设置变量的副本,当您的代码工作时,将最后一个值粘贴到变量对话框中。
将Java调用放入.BAT
文件并双击它。这将每次创建一个新控制台(从而复制系统变量的当前值)。
注意:如果您还有一个用户变量CLASSPATH
,那么它将隐藏您的系统变量。这就是为什么最好将 Java 程序的调用放入 .BAT
文件并在其中设置类路径(使用 set CLASSPATH=
)而不是依赖全局系统或用户变量。
这也确保您可以在您的计算机上运行多个 Java 程序,因为它们必然具有不同的类路径。
【讨论】:
【参考方案11】:我的答案与问题中所问的不完全一样。相反,我给出了一个解决方案,我们可以多么容易地从我们的项目类路径中将文件读入 Java 应用程序。
例如,假设配置文件名 example.xml 位于如下路径中:-
com.myproject.config.dev
我们的java可执行类文件在下面的路径中:-
com.myproject.server.main
现在只需检查上述路径,这是最近的公共目录/文件夹,您可以从中访问 dev 和 main 目录/文件夹(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 不提供流参数的情况下很有用。【参考方案12】:如果你在 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;
【讨论】:
【参考方案13】:我正在使用 webshpere 应用程序服务器,并且我的 Web 模块是基于 Spring MVC 构建的。 Test.properties
位于资源文件夹中,我尝试使用以下内容加载此文件:
this.getClass().getClassLoader().getResourceAsStream("Test.properties");
this.getClass().getResourceAsStream("/Test.properties");
以上代码均未加载该文件。
但在以下代码的帮助下,属性文件已成功加载:
Thread.currentThread().getContextClassLoader().getResourceAsStream("Test.properties");
感谢用户“user1695166”。
【讨论】:
欢迎来到 Stack Overflow!请不要添加“谢谢”作为答案,即使您还部分地提供了您的解决方案是如何进行的,如果您的解决方案与另一个帖子相同,则不需要添加。在网站上投入一些时间后,您将获得足够的 privileges 来支持您喜欢的答案,这是 Stack Overflow 表达谢谢的方式。【参考方案14】:使用org.apache.commons.io.FileUtils.readFileToString(new File("src/test/resources/sample-data/fileName.txt"));
【讨论】:
不应使用对 src 的引用...在最终工件中不起作用。【参考方案15】:不要使用 getClassLoader() 方法并在文件名前使用“/”。 “/”很重要
this.getClass().getResourceAsStream("/SomeTextFile.txt");
【讨论】:
使用前导/
与使用getClassLoader()
方法效果完全相同。【参考方案16】:
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();
【讨论】:
不以任何方式回答问题。【参考方案17】:您必须将“系统变量”放在 java 类路径中。
【讨论】:
我把系统变量本身。 “系统变量”是 Java CLASSPATH。答案没有意义。 完全正确...甚至不记得写过这个答案:)以上是关于如何在 Java 中真正从类路径中读取文本文件的主要内容,如果未能解决你的问题,请参考以下文章