我一直在使用下面的成语一段时间了 . 它似乎是最广泛的,至少在我访问过的网站上 .
是否有更好/不同的方式将文件读入Java中的字符串?
private String readFile(String file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader (file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
try {
while((line = reader.readLine()) != null) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
return stringBuilder.toString();
} finally {
reader.close();
}
}
30 回答
使用Java 7,这是我读取UTF-8文件的首选选项:
从Java 7开始,JDK具有新的
java.nio.file
API,它提供了许多快捷方式,因此简单文件操作并不总是需要第三方库 .如果您涉及第三方库(例如Commons I/O),则可以使用Scanner类:
使用JDK 8或以上版本:
no external libraries used
您可以从文件内容创建一个新的String对象(使用
java.nio.file
包中的类):这个使用方法
RandomAccessFile.readFully
,似乎可以从JDK 1.0获得!收集了从磁盘或网络读取文件为字符串的所有可能方法 .
\A
的扫描仪类 . 它与输入的开头相匹配 .java.nio.file.Files.readAllBytes
)BufferedReader
使用InputStreamReader
.使用main方法访问上述方法的示例 .
@看到
来自this page一个非常精益的解决方案:
要么
如果要设置charset
在Scanner之后按Ctrl F'ing后,我认为也应该列出Scanner解决方案 . 以最容易阅读的方式,它是这样的:
如果您使用Java 7或更新版本(并且您真的应该),请考虑使用try-with-resources来使代码更易于阅读 . 没有更多关闭垃圾的东西 . 但这主要是一种风格选择 .
我发布这个主要是为了完成主义,因为如果你需要做很多事情,java.nio.file.Files应该有更好的工作 .
我的建议是使用Files#readAllBytes(Path)获取所有字节,并将其提供给新的String(byte[] Charset)以从中获取可信任的字符串 . Charsets在你的一生中对你意味着什么,所以现在要小心这些东西 .
其他人给了代码和东西,我不想偷走他们的荣耀 . ;)
您可以尝试Scanner和File类,几行解决方案
在同一主题上有一个变体,它使用for循环而不是while循环来限制行变量的范围 . 它是否“更好”是个人品味的问题 .
Guava有一种类似于Commons IOUtils的方法,Willi aus Rohr提到:
EDIT by Oscar Reyes
这是引用库中的(简化)底层代码:
Edit (作者Jonik):以上内容与最近的Guava版本的源代码不符 . 对于当前源,请参阅com.google.common.io包中的类Files,CharStreams,ByteSource和CharSource .
使用this library,它是一行:
基于@ erickson的回答,您可以使用:
我还不能评论其他条目,所以我会把它留在这里 .
这里最好的答案之一(https://stackoverflow.com/a/326448/1521167):
还有一个缺陷 . 它总是将新行char放在字符串的末尾,这可能会导致一些奇怪的错误 . 我的建议是将其改为:
从java 7开始,你就可以这样做 .
该代码将规范化换行符,这可能是你真正想做的事情,也可能不是 .
这里's an alternative which doesn' t这样做,哪个(IMO)比NIO代码更容易理解(虽然它仍然使用
java.nio.charset.Charset
):从文件中读取所有文本
这是Java 7的一个紧凑,健壮的习惯用法,包含在一个实用程序方法中:
从文件中读取文本行
Java 7添加了convenience method to read a file as lines of text,,表示为
List<String>
. 这种方法是"lossy",因为行分隔符是从每行的末尾剥离的 .在Java 8中,
BufferedReader
添加了一个新方法lines()来生成一个Stream<String>
. 如果在读取文件时遇到IOException
,它将包装在UncheckedIOException中,因为Stream
不接受抛出已检查异常的lambdas .还有一个
Files.lines()
方法可以执行非常相似的操作,直接返回Stream<String>
. 但我不喜欢它 .Stream
需要close()
电话;这在API上记录很少,我怀疑很多人甚至没有注意到Stream
有一个close()
方法 . 所以你的代码看起来非常相似,如下所示:不同的是你有一个
Stream
分配给一个变量,我尝试避免这种做法,以便我不小心尝试两次调用流 .内存利用率
保留换行符的第一种方法可以暂时需要几倍于文件大小的内存,因为短时间内原始文件内容(字节数组)和解码后的字符(即使编码也是16位)因为文件中的8位)一次驻留在内存中 . 最安全的是应用于您知道相对于可用内存较小的文件 .
读取线的第二种方法通常更多内存效率高,因为用于解码的输入字节缓冲区不需要包含整个文件 . 但是,它仍然不适合相对于可用内存非常大的文件 .
对于读取大文件,您需要为程序设计不同的设计,一个从流中读取一块文本,处理它,然后继续下一个,重复使用相同的固定大小的内存块 . 在这里,"large"取决于计算机规格 . 如今,这个阈值可能是几千兆字节的RAM . 如果您的输入"records"碰巧是单独的行,则使用
Stream<String>
的第三种方法是执行此操作的一种方法 . (使用readLine()
的readLine()
方法是与此方法等效的过程 . )字符编码
原始帖子中的示例中缺少的一件事是字符编码 . 在某些特殊情况下,平台默认值是您想要的,但它们很少见,您应该能够证明您的选择 .
StandardCharsets类为所有Java运行时所需的编码定义了一些常量:
平台默认值可从the Charset class本身获得:
注意:这个答案很大程度上取代了我的Java 6版本 . Java 7的实用程序安全地简化了代码,使用映射字节缓冲区的旧答案阻止了读取的文件被删除,直到映射的缓冲区被垃圾收集 . 您可以通过此答案中的“已编辑”链接查看旧版本 .
Commons FileUtils.readFileToString:
该类(间接)使用的代码是:
IOUtils.java在Apache Licence 2.0下 .
它与Ritche_W使用的非常相似 .
用户
java.nio.Files
读取所有文件行 .从JDK 11开始:
Java试图在其所有方面都非常通用和灵活 . 因此,在脚本语言中相对简单的东西(您的代码将在python中替换为“
open(file).read()
”)要复杂得多 . 除了使用外部库(如提到的Willi aus Rohr)之外,似乎没有任何更短的方法 . 你的选择:使用外部库 .
将此代码复制到所有项目中 .
创建自己的迷你库,其中包含您经常使用的功能 .
你最好的选择可能是第二个,因为它的依赖性最小 .
如果您需要字符串处理(并行处理),Java 8具有出色的Stream API .
JDK示例
sample/lambda/BulkDataOperations
中提供了更多示例,可以从Oracle Java SE 8 download page下载另一个班轮示例
如果您无权访问
Files
类,则可以使用本机解决方案 .使用来自Apache commons-io的IOUtils与StringWriter组合的灵活解决方案:
它适用于任何阅读器或输入流(不仅仅是文件),例如从URL读取时 .
在一行(Java 8)中,假设您有一个Reader:
如果是文本文件,为什么不使用apache commons-io?
它有以下方法
如果您希望将行作为列表使用
将文件读取为二进制文件并在结尾处进行转换
请注意,在使用
fileInputStream.available()
时,返回的整数不必表示实际文件大小,而是系统应该能够在不阻塞IO的情况下从流中读取的猜测字节数 . 一种安全而简单的方式可能看起来像这样应该认为这种方法适用于UTF-8等多字节字符编码 .
此外,如果您的文件恰好在jar中,您也可以使用:
例如,如果你的jar是,那么路径应该以
/
开头然后你想像这样调用它:
.......