【问题标题】:How to really read text file from classpath in Java如何在 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

【问题讨论】:

    标签: java classpath


    【解决方案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 接口,您可以通过 InputStreamURLURI 访问资源文件。将资源类型更改为例如文件系统资源只需更改实例即可。

    【讨论】:

    • 您能否提供一个示例代码,说明如何在文件 I/O 中使用它?我找不到关于如何在互联网上使用它的体面显式直截了当的方法:((((
    • 像魅力一样工作。提供的一个衬垫就是您所需要的。如果您不知道如何从流中获取字符串,请使用其他示例中的流解析。
    • 我在弄清楚如何处理资源变量时也遇到了一些麻烦。我已经更详细地编辑了答案
    • 我已经在使用 Spring 并尝试“纯 java”方式。 getResource、getResourceAsStream 等之间的差异,没有好的工作示例,这让我很生气。这是一个完美的封装示例,所以我不必在意。
    • 请注意,如果您将项目打包到 jar 中,您应该使用 InputStream。如果您使用 File 它可以在您的 IDE 中工作,但如果您从 jar 中测试它会失败。如果你真的需要一个文件试试stackoverflow.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 解决方案 - 很少有人使用这个很棒的 AP​​I,真可惜。
    • 读入单个字符串试试。新字符串(Files.readAllBytes(Paths.get(MyClass.class.getResource(resource).toURI())));
    • 对我来说最好的解决方案,因为它不需要任何依赖项,例如 Spring 或 Commons IO。
    • 如果您的资源文件在 jar 中,这将失败,例如一个Maven模块。在这种情况下,您需要使用类似SpringStreamUtils.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 的回答中的例子吗?
    【解决方案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);
        }
    }
    

    注意:
    IOUtilsCommons IO 的一部分。

    这样称呼它:

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

    【讨论】:

      【解决方案10】:

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

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

      有以下解决方案:

      1. 每次更改后启动一个新控制台

      2. 在控制台中使用set CLASSPATH=... 在控制台中设置变量的副本,当您的代码工作时,将最后一个值粘贴到变量对话框中。

      3. 将Java调用放入.BAT文件并双击它。这将每次创建一个新控制台(从而复制系统变量的当前值)。

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

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

      【讨论】:

        【解决方案11】:

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

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

        com.myproject.config.dev

        我们的java可执行类文件在下面的路径中:-

        com.myproject.server.main

        现在只需检查上述路径,这是最近的公共目录/文件夹,您可以从中访问 devma​​in 目录/文件夹(com.myproject. server.main - 我们的应用程序的 java 可执行类所在的位置) - 我们可以看到它是 myproject 文件夹/目录,这是我们可以访问 example.xml 文件的最近的公共目录/文件夹。因此,从驻留在文件夹/目录 ma​​in 中的 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 位于资源文件夹中,我尝试使用以下内容加载此文件:

          1. this.getClass().getClassLoader().getResourceAsStream("Test.properties");
          2. 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。答案没有意义。
          • 完全正确...甚至不记得写过这个答案:)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-05-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-21
          • 1970-01-01
          相关资源
          最近更新 更多