实用程序将资源文本文件读取为String(Java)[关闭]


215

是否有任何实用程序可帮助将资源中的文本文件读取为字符串。我想这是一个很普遍的要求,但是在谷歌搜索后找不到任何实用程序。


1
请说明“资源文本文件”与“资源中的文本文件”的含义-理解要实现的目标并不容易。

那只是类路径下的一个文本文件,例如“ classpath *:mytext / text.txt”
Loc Phan

Answers:


301

是的,番石榴Resources课堂上提供了这一点。例如:

URL url = Resources.getResource("foo.txt");
String text = Resources.toString(url, StandardCharsets.UTF_8);

21
@JonSkeet这很好,但是对于Web应用程序,它可能不是最佳解决方案,getResource正在使用的实现,Resource.class.getClassLoader但是在Web应用程序中,这可能不是“您的”类加载器,因此建议(例如[1]中的)使用Thread.currentThread().getContextClassLoader().getResourceAsStream而是(参考[1]:stackoverflow.com/questions/676250/…
Eran Medan 2013年

2
@EranMedan:是的,如果要使用上下文类加载器,则需要显式使用它。
乔恩·斯基特

6
在特殊情况下,当资源靠近您的类时,您可以这样做Resources.toString(MyClass.getResource("foo.txt"), Charsets.UTF_8),以确保使用正确的类加载器。
Bogdan Calmac'3

2
com.google.common.io.Resources根据SonarQube
Ghilteras,

1
guava已经改变了实现。对于番石榴23,实现如下。ClassLoader loader = MoreObjects.firstNonNull( Thread.currentThread().getContextClassLoader(), Resources.class.getClassLoader());
XXY

170

您可以使用旧的Stupid Scanner技巧 oneliner来做到这一点,而无需使用番石榴之类的任何其他依赖项:

String text = new Scanner(AppropriateClass.class.getResourceAsStream("foo.txt"), "UTF-8").useDelimiter("\\A").next();

伙计们,除非您确实需要,否则请不要使用第三方的东西。JDK中已经有很多功能。


41
避免第三者是一个合理的原则。不幸的是,核心库似乎对建模实际用例过敏。查看Java 7的文件,并告诉我为什么不包括从类路径资源读取所有内容的原因?或至少使用标准化的“文件系统”。
Dilum Ranatunga 2014年

3
是否也需要关闭流?番石榴在内部关闭流。
virgo47 2014年

也为我工作得很漂亮!我也同意第三方的观点:在许多答案中,默认响应似乎总是使用某些第三方库-来自Apache或其他人。
Terje Dahl 2015年

1
更改CartApplication.class.getResourceAsStreamCartApplication.class.getClassLoader().getResourceAsStream在当前jar中加载资源。.如srm / test / resources
Chris DaMour

5
在使用此功能时,我完全不同意避免使用第三方包装。在Java中,唯一易于将文件读取为字符串的方法就是使用扫描器技巧,这一事实令人非常遗憾。使用第三方库的替代方法是每个人都将创建自己的包装器。如果您对此类操作有很多需求,那么IO的Guava绝对会成功。我会同意的是,如果您的代码中只有一个地方想要这样做,则不应导入第三方包装。那将是过分的imo。
肯尼·卡森

90

对于Java 7:

new String(Files.readAllBytes(Paths.get(getClass().getResource("foo.txt").toURI())));

3
请说明为什么这样做有效,为什么它比其他替代方法更好,以及需要的任何性能/编码注意事项。
nanofarad 2014年

5
在Java 1.7中是nio 2。这是Java的固有功能。对于编码,请使用新的String(bytes,StandardCharsets.UTF_8)
Kovalsky Dmitryi 2014年

5
在我的情况下,我需要,getClass().getClassLoader()但否则要有很好的解决方案!
Emmanuel Touzery

3
将应用程序打包到罐子中后,这将无法工作。
Daniel Bo

65

简洁,易于使用的Java 8+解决方案

如果您使用的是Java 8或更高版本,则下面的简单方法就可以了:

/**
 * Reads given resource file as a string.
 *
 * @param fileName path to the resource file
 * @return the file's contents
 * @throws IOException if read fails for any reason
 */
static String getResourceFileAsString(String fileName) throws IOException {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    try (InputStream is = classLoader.getResourceAsStream(fileName)) {
        if (is == null) return null;
        try (InputStreamReader isr = new InputStreamReader(is);
             BufferedReader reader = new BufferedReader(isr)) {
            return reader.lines().collect(Collectors.joining(System.lineSeparator()));
        }
    }
}

它也可以与jar文件中的资源一起使用

关于文本编码:InputStreamReader如果您未指定默认字符集,则会使用默认系统字符集。您可能需要自己指定它以避免解码问题,如下所示:

new InputStreamReader(isr, StandardCharsets.UTF_8);

避免不必要的依赖

总是喜欢不依赖庞大的胖图书馆。除非您已经使用Guava或Apache Commons IO来执行其他任务,否则将这些库添加到项目中只是为了能够从文件中读取似乎有点过多。

“简单”的方法?你肯定是在逗我

我了解到纯Java不能很好地完成这样的简单任务。例如,这是我们从Node.js中的文件读取的方式:

const fs = require("fs");
const contents = fs.readFileSync("some-file.txt", "utf-8");

简单易读(尽管人们仍然喜欢依赖于许多依赖,这主要是由于无知)。或在Python中:

with open('some-file.txt', 'r') as f:
    content = f.read()

很遗憾,但是对于Java标准而言,它仍然很简单,您所要做的就是将上述方法复制到您的项目中并使用它。我什至不要求您了解其中发生的事情,因为这对任何人都没有关系。它只是有效,期间:-)


4
@zakmck,请尝试使您的评论具有建设性。随着您成长为成熟的开发人员,您会发现有时确实希望“重新发明轮子”。例如,您可能需要将二进制文件的大小保持在阈值以下。库通常会使您的应用程序大小增加几个数量级。有人可能会说与您所说的相反:“无需编写代码。是的,让我们每次都导入库”。您是否真的愿意导入一个库以节省3行代码?我敢打赌,添加库将使您的LOC增加更多。关键是平衡。
Lucio Paiva

3
好吧,并不是每个人都在云上运行东西。例如,到处都有运行Java的嵌入式系统。考虑到您提到自己将接受直接在自己的代码中直接使用JDK的建议,我只是没有批评批评提供完全有效方法的答案。无论如何,让我们尝试严格保留评论以帮助改善答案,而不是讨论意见。
Lucio Paiva

1
好的仅JDK解决方案。我只会添加检查InputStream变量is是否为null
scrutari

2
真好 我用这个 您也可以考虑关闭流/阅读器。
dimplex

1
@RobertBain我编辑了答案以添加有关字符集警告的信息。让我知道您是否发现AWS中的类加载器出了什么问题,因此我也可以将其添加到答案中。谢谢!
卢西奥·帕瓦

57

番石榴有一个“ toString”方法,用于将文件读入字符串:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

String content = Files.toString(new File("/home/x1/text.log"), Charsets.UTF_8);

此方法不需要文件位于类路径中(如Jon Skeet先前的回答)。


2
或者,如果它是输入流,那么番石榴也有很好的方法String stringFromStream = CharStreams.toString(new InputStreamReader(resourceAsStream, "UTF-8"));
Eran Medan 2013年

1
在Guava 24.1中已弃用
Andrey

47

yegor256 使用Apache Commons IO找到了一个不错的解决方案

import org.apache.commons.io.IOUtils;

String text = IOUtils.toString(this.getClass().getResourceAsStream("foo.xml"),
                               "UTF-8");

如果这种情况不可用,我更喜欢使用“”
user833970

11
同样紧凑,但输入流已正确关闭:IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
Bogdan Calmac'3

1
如果该解决方案不起作用,请尝试将其添加getClassLoader()到方法链中: String text = IOUtils.toString( getClass().getClassLoader().getResourceAsStream("foo.xml"), StandardCharsets.UTF_8);
Abdull

39

apache-commons-io具有实用程序名称FileUtils

URL url = Resources.getResource("myFile.txt");
File myFile = new File(url.toURI());

String content = FileUtils.readFileToString(myFile, "UTF-8");  // or any other encoding

1
为什么必须指定编码,但我不知道。如果读取文件,我只是想要其中的内容,它应该弄清楚它的编码方式就像我的编辑器一样。在记事本或++中打开时,我不告诉它应使用哪种编码。我正在使用此方法,然后再使用writeStringToFile ...,但是内容有所不同。我在克隆的文件中得到了奇怪的标记。.我不明白为什么我必须指定编码。
mmm

11
@Hamidan,选择正确的编码是一个非常复杂的算法。它通常在文本编辑器中实现,但有时无法检测到正确的编码。我不希望文件读取API嵌入这样复杂的算法来读取我的文件。
文森特·罗伯特

1
@SecretService同样,这些算法利用诸如操作系统语言,语言环境和其他区域设置之类的信息,这意味着在不指定编码的情况下读取文件可能对您的设置有效,而对其他人则无效。
Feuermurmel 2014年

Apache FileUtilsreadLines(文件)和copyURLToFile(URL,tempFile)。
Yash

2
我认为如果在罐子里找到资源,这将行不通。那就不会是文件了。
Ville Oikarinen

16

我自己经常遇到这个问题。为了避免依赖小型项目,我经常在不需要common io或类似的东西时编写一个小型实用程序函数。这是将文件内容加载到字符串缓冲区中的代码:

StringBuffer sb = new StringBuffer();

BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("path/to/textfile.txt"), "UTF-8"));
for (int c = br.read(); c != -1; c = br.read()) sb.append((char)c);

System.out.println(sb.toString());   

在这种情况下,指定编码重要,因为您可能已经在UTF-8中编辑了文件,然后将其放在jar中,并且打开文件的计算机可能会将CP-1251作为其本机文件编码(例如) ; 因此在这种情况下,您永远不会知道目标编码,因此显式编码信息至关重要。同样,通过char读取文件char的循环看起来效率很低,但是它用在BufferedReader上,因此实际上非常快。


15

您可以使用以下代码形式的Java

new String(Files.readAllBytes(Paths.get(getClass().getResource("example.txt").toURI())));

导入“文件”和“路径”类需要什么导入语句?
Steve Scherer

1
两者都是java.nio.file软件包的一部分,可从JDK 7+获得
Raghu K Nair16年

在jar文件中时不起作用。
6

4

如果要从项目资源中获取字符串,例如项目中src / main / resources中的文件testcase / foo.json,请执行以下操作:

String myString= 
 new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("testcase/foo.json").toURI())));

请注意,在其他一些示例中,缺少getClassLoader()方法。


2

使用Apache Commons的FileUtils。它有一个方法readFileToString


文件仅适用于属于文件的类路径资源。如果它们是.jar文件中的元素,或者是胖jar的一部分,则不是其他类加载器实现之一。
toolforger

2

我正在使用以下内容从中读取资源文件classpath

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Scanner;

public class ResourceUtilities
{
    public static String resourceToString(String filePath) throws IOException, URISyntaxException
    {
        try (InputStream inputStream = ResourceUtilities.class.getClassLoader().getResourceAsStream(filePath))
        {
            return inputStreamToString(inputStream);
        }
    }

    private static String inputStreamToString(InputStream inputStream)
    {
        try (Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"))
        {
            return scanner.hasNext() ? scanner.next() : "";
        }
    }
}

无需第三方依赖性。


1

通过一组静态导入,Guava解决方案可以非常紧凑地实现以下功能:

toString(getResource("foo.txt"), UTF_8);

需要以下进口:

import static com.google.common.io.Resources.getResource
import static com.google.common.io.Resources.toString
import static java.nio.charset.StandardCharsets.UTF_8

1
package test;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        try {
            String fileContent = getFileFromResources("resourcesFile.txt");
            System.out.println(fileContent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //USE THIS FUNCTION TO READ CONTENT OF A FILE, IT MUST EXIST IN "RESOURCES" FOLDER
    public static String getFileFromResources(String fileName) throws Exception {
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream stream = classLoader.getResourceAsStream(fileName);
        String text = null;
        try (Scanner scanner = new Scanner(stream, StandardCharsets.UTF_8.name())) {
            text = scanner.useDelimiter("\\A").next();
        }
        return text;
    }
}

1

至少从Apache commons-io 2.5开始,IOUtils.toString()方法支持URI参数并返回位于类路径上jar内的文件的内容:

IOUtils.toString(SomeClass.class.getResource(...).toURI(), ...)

1

我喜欢akosicki的“愚蠢扫描程序技巧”答案。这是我所见到的最简单的,没有外部依赖性的,可以在Java 8中运行的(实际上一直到Java 5为止)。如果您可以使用Java 9或更高版本(从InputStream.readAllBytes()Java 9开始添加),这是一个更简单的答案:

String text = new String(AppropriateClass.class.getResourceAsStream("foo.txt").readAllBytes());

0

Files.readLines()如果您想List<String>逐行返回值,番石榴还具有:

List<String> lines = Files.readLines(new File("/file/path/input.txt"), Charsets.UTF_8);

请参考此处以比较从文本文件中获取3种方法(BufferedReader与Guava的Files对比与Guava的对比ResourcesString


什么是字符集类?不是本地人
e-info128

@ e-info128 Charsets也在Guava中。看到这个:google.github.io/guava/releases/23.0/api/docs
philipjkim

0

这是我的方法很好

public String getFileContent(String fileName) {
    String filePath = "myFolder/" + fileName+ ".json";
    try(InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath)) {
        return IOUtils.toString(stream, "UTF-8");
    } catch (IOException e) {
        // Please print your Exception
    }
}

2
IOUtils来自哪里?来源应明确引用。
ehecatl


0

如果包含番石榴,则可以使用:

String fileContent = Files.asCharSource(new File(filename), Charset.forName("UTF-8")).read();

(其他解决方案提到了番石榴的其他方法,但已弃用)


0

以下鳕鱼对我有用:

compile group: 'commons-io', name: 'commons-io', version: '2.6'

@Value("classpath:mockResponse.json")
private Resource mockResponse;

String mockContent = FileUtils.readFileToString(mockResponse.getFile(), "UTF-8");


0

我做了这样的无依赖静态方法:

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

public class ResourceReader {
    public  static String asString(String resourceFIleName) {
        try  {
            return new String(Files.readAllBytes(Paths.get(new CheatClassLoaderDummyClass().getClass().getClassLoader().getResource(resourceFIleName).toURI())));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
class CheatClassLoaderDummyClass{//cheat class loader - for sql file loading
}

0

我喜欢Apache commons utils用于此类内容,并在测试时广泛使用此确切的用例(从类路径读取文件),尤其是/src/test/resources作为单元/集成测试的一部分读取JSON文件时。例如

public class FileUtils {

    public static String getResource(String classpathLocation) {
        try {
            String message = IOUtils.toString(FileUtils.class.getResourceAsStream(classpathLocation),
                    Charset.defaultCharset());
            return message;
        }
        catch (IOException e) {
            throw new RuntimeException("Could not read file [ " + classpathLocation + " ] from classpath", e);
        }
    }

}

为了进行测试,最好抓住IOException并抛出一个RuntimeException-您的测试类可能看起来像例如

    @Test
    public void shouldDoSomething () {
        String json = FileUtils.getResource("/json/input.json");

        // Use json as part of test ...
    }

-2
public static byte[] readResoureStream(String resourcePath) throws IOException {
    ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
    InputStream in = CreateBffFile.class.getResourceAsStream(resourcePath);

    //Create buffer
    byte[] buffer = new byte[4096];
    for (;;) {
        int nread = in.read(buffer);
        if (nread <= 0) {
            break;
        }
        byteArray.write(buffer, 0, nread);
    }
    return byteArray.toByteArray();
}

Charset charset = StandardCharsets.UTF_8;
String content = new   String(FileReader.readResoureStream("/resource/...*.txt"), charset);
String lines[] = content.split("\\n");

请在回答中添加简短说明。
Nikolay Mihaylov
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.