提问人:OscarRyz 提问时间:11/29/2008 最后编辑:NamanOscarRyz 更新时间:1/24/2023 访问量:1680500
如何从文件的内容创建 Java 字符串?
How do I create a Java string from the contents of a file?
问:
我已经使用下面的成语一段时间了。它似乎是最普遍的,至少在我访问过的网站上是这样。
在 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();
}
}
答:
如果您愿意使用外部库,请查看 Apache Commons IO (200KB JAR)。它包含一个 org.apache.commons.io.FileUtils.readFileToString()
方法,允许您用一行代码将整个读入 a。File
String
例:
import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;
public String readFile() throws IOException {
File file = new File("data.txt");
return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}
Java 试图在它所做的一切方面都非常通用和灵活。因此,在脚本语言中相对简单的东西(您的代码将在 python 中替换为“”)要复杂得多。除了使用外部库(如Willi aus Rohr提到的那样)之外,似乎没有比这更短的方法了。您的选择:open(file).read()
- 使用外部库。
- 将此代码复制到所有项目中。
- 创建您自己的迷你库,其中包含您经常使用的函数。
你最好的选择可能是第二个,因为它的依赖性最少。
评论
byte[] bytes = Files.readAllBytes(someFile.toPath());
读取文件中的所有文本
Java 11 添加了 readString() 方法来读取小文件,保留了行终止符:String
String content = Files.readString(path, encoding);
对于 Java 7 和 11 之间的版本,这里有一个紧凑、健壮的习惯用语,包含在实用程序方法中:
static String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
从文件中读取文本行
Java 7 添加了一种方便的方法,可以将文件读取为文本行,表示为 .这种方法是“有损的”,因为行分隔符是从每行的末尾剥离的。List<String>
List<String> lines = Files.readAllLines(Paths.get(path), encoding);
Java 8 添加了 Files.lines()
方法来生成 .同样,此方法是有损的,因为行分隔符被剥离。如果在读取文件时遇到 ,则将其包装在 UncheckedIOException
中,因为不接受引发已检查异常的 lambda。Stream<String>
IOException
Stream
try (Stream<String> lines = Files.lines(path, encoding)) {
lines.forEach(System.out::println);
}
这确实需要一个 close()
调用;这在 API 上的记录很少,我怀疑很多人甚至没有注意到有一个方法。请务必使用 ARM 块,如下所示。Stream
Stream
close()
如果您使用的是文件以外的源,则可以改用 lines()
方法。BufferedReader
内存利用率
如果您的文件相对于可用内存足够小,则一次读取整个文件可能会正常工作。但是,如果您的文件太大,一次读取一行,对其进行处理,然后在继续下一行之前丢弃它可能是更好的方法。以这种方式进行流处理可以消除总文件大小作为内存需求的一个因素。
字符编码
原始帖子中的示例中缺少的一件事是字符编码。这种编码通常无法从文件本身确定,并且需要元数据(如 HTTP 标头)来传达此重要信息。
StandardCharsets
类为所有 Java 运行时所需的编码定义了一些常量:
String content = readFile("test.txt", StandardCharsets.UTF_8);
平台默认值可从 Charset
类本身获得:
String content = readFile("test.txt", Charset.defaultCharset());
在一些特殊情况下,平台默认是您想要的,但这种情况很少见。您应该能够证明您的选择是合理的,因为平台默认是不可移植的。一个可能正确的例子是在读取标准输入或写入标准输出时。
注意:这个答案很大程度上取代了我的 Java 6 版本。Java 7 的实用程序安全地简化了代码,而旧的答案使用映射的字节缓冲区,在映射的缓冲区被垃圾回收之前,可以防止读取的文件被删除。您可以通过此答案上的“已编辑”链接查看旧版本。
评论
Files.readString(…)
如果你正在寻找一个不涉及第三方库的替代方案(例如Commons I/O),你可以使用Scanner类:
private String readFile(String pathname) throws IOException {
File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
try (Scanner scanner = new Scanner(file)) {
while(scanner.hasNextLine()) {
fileContents.append(scanner.nextLine() + System.lineSeparator());
}
return fileContents.toString();
}
}
该代码将规范化换行符,这可能是也可能不是您真正想要做的事情。
这里有一个替代方案,它不这样做,并且 (IMO) 比 NIO 代码更容易理解(尽管它仍然使用):java.nio.charset.Charset
public static String readFile(String file, String csName)
throws IOException {
Charset cs = Charset.forName(csName);
return readFile(file, cs);
}
public static String readFile(String file, Charset cs)
throws IOException {
// No real need to close the BufferedReader/InputStreamReader
// as they're only wrapping the stream
FileInputStream stream = new FileInputStream(file);
try {
Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
StringBuilder builder = new StringBuilder();
char[] buffer = new char[8192];
int read;
while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
builder.append(buffer, 0, read);
}
return builder.toString();
} finally {
// Potential issue here: if this throws an IOException,
// it will mask any others. Normally I'd use a utility
// method which would log exceptions and swallow them
stream.close();
}
}
评论
同一主题上有一个变体,它使用 for 循环而不是 while 循环来限制 line 变量的范围。是否“更好”是个人品味的问题。
for(String line = reader.readLine(); line != null; line = reader.readLine()) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
评论
line
public static String slurp (final File file)
throws IOException {
StringBuilder result = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(file));
try {
char[] buf = new char[1024];
int r = 0;
while ((r = reader.read(buf)) != -1) {
result.append(buf, 0, r);
}
}
finally {
reader.close();
}
return result.toString();
}
评论
cannot find symbol
Guava 的方法类似于 Willi aus Rohr 提到的 Commons IOUtils 中的方法:
import com.google.common.base.Charsets;
import com.google.common.io.Files;
// ...
String text = Files.toString(new File(path), Charsets.UTF_8);
PiggyPiglet
的编辑已弃用,将于 2019 年 10 月删除。请改用Files#toString
Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();
奥斯卡·雷耶斯(Oscar Reyes)编辑
这是引用库上的(简化)底层代码:
InputStream in = new FileInputStream(file);
byte[] b = new byte[file.length()];
int len = b.length;
int total = 0;
while (total < len) {
int result = in.read(b, total, len - total);
if (result == -1) {
break;
}
total += result;
}
return new String( b , Charsets.UTF_8 );
编辑(由 Jonik 提供):以上内容与最近 Guava 版本的源代码不匹配。有关当前源,请参阅包中的 Files、CharStreams、ByteSource 和 CharSource 类 com.google.common.io。
评论
将文件读取为二进制文件并在最后进行转换
public static String readFileAsString(String filePath) throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
try {
long len = new File(filePath).length();
if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
byte[] bytes = new byte[(int) len];
dis.readFully(bytes);
return new String(bytes, "UTF-8");
} finally {
dis.close();
}
}
基于 Scanner
的非常精益的解决方案:
Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block
或者,如果要设置字符集:
Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block
或者,使用一个 try-with-resources 块,它将调用您:scanner.close()
try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
String text = scanner.useDelimiter("\\A").next();
}
请记住,构造函数可以抛出 .别忘了导入 和 .Scanner
IOException
java.io
java.util
资料来源:Pat Niemeyer 的博客
评论
如果是文本文件,为什么不使用 apache commons-io?
它有以下方法
public static String readFileToString(File file) throws IOException
如果希望将行作为列表,请使用
public static List<String> readLines(File file) throws IOException
这个用的就是这个方法,好像是JDK 1.0可以买到的!RandomAccessFile.readFully
public static String readFileContent(String filename, Charset charset) throws IOException {
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(filename, "r");
byte[] buffer = new byte[(int)raf.length()];
raf.readFully(buffer);
return new String(buffer, charset);
} finally {
closeStream(raf);
}
}
private static void closeStream(Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException ex) {
// do nothing
}
}
}
将 Apache commons-io 中的 IOUtils 与 StringWriter 结合使用的灵活解决方案:
Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
IOUtils.copy(input, output);
} finally {
input.close();
}
String fileContents = output.toString();
它适用于任何读取器或输入流(而不仅仅是文件),例如从 URL 读取时。
import java.nio.file.Files;
.......
String readFile(String filename) {
File f = new File(filename);
try {
byte[] bytes = Files.readAllBytes(f.toPath());
return new String(bytes,"UTF-8");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
评论
new String(Files.readAllBytes(Paths.get(filename)));
请注意,使用返回的整数时,不必表示实际文件大小,而是系统应该能够在不阻塞 IO 的情况下从流中读取的猜测字节数。一种安全而简单的方法可以看起来像这样fileInputStream.available()
public String readStringFromInputStream(FileInputStream fileInputStream) {
StringBuffer stringBuffer = new StringBuffer();
try {
byte[] buffer;
while (fileInputStream.available() > 0) {
buffer = new byte[fileInputStream.available()];
fileInputStream.read(buffer);
stringBuffer.append(new String(buffer, "ISO-8859-1"));
}
} catch (FileNotFoundException e) {
} catch (IOException e) { }
return stringBuffer.toString();
}
应该考虑的是,这种方法不适用于像 UTF-8 这样的多字节字符编码。
评论
available()
available()
我还不能评论其他条目,所以我就把它留在这里。
这里最好的答案之一(https://stackoverflow.com/a/326448/1521167):
private String readFile(String pathname) throws IOException {
File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
Scanner scanner = new Scanner(file);
String lineSeparator = System.getProperty("line.separator");
try {
while(scanner.hasNextLine()) {
fileContents.append(scanner.nextLine() + lineSeparator);
}
return fileContents.toString();
} finally {
scanner.close();
}
}
还有一个缺陷。它总是在字符串的末尾放置新行字符,这可能会导致一些奇怪的错误。我的建议是将其更改为:
private String readFile(String pathname) throws IOException {
File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int) file.length());
Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
String lineSeparator = System.getProperty("line.separator");
try {
if (scanner.hasNextLine()) {
fileContents.append(scanner.nextLine());
}
while (scanner.hasNextLine()) {
fileContents.append(lineSeparator + scanner.nextLine());
}
return fileContents.toString();
} finally {
scanner.close();
}
}
评论
如果你需要字符串处理(并行处理),Java 8 有很棒的 Stream API。
String result = Files.lines(Paths.get("file.txt"))
.parallel() // for parallel processing
.map(String::trim) // to change line
.filter(line -> line.length() > 2) // to filter some lines by a predicate
.collect(Collectors.joining()); // to join lines
JDK 示例中提供了更多示例,可从 Oracle Java SE 8 下载页面下载sample/lambda/BulkDataOperations
另一个衬垫示例
String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
评论
Files.lines(Paths.get("file.txt"))
如果您无权访问该类,则可以使用本机解决方案。Files
static String readFile(File file, String charset)
throws IOException
{
FileInputStream fileInputStream = new FileInputStream(file);
byte[] buffer = new byte[fileInputStream.available()];
int length = fileInputStream.read(buffer);
fileInputStream.close();
return new String(buffer, 0, length, charset);
}
评论
在 Scanner 之后的 Ctrl+F'ing 之后,我认为也应该列出 Scanner 解决方案。以最容易阅读的方式,它是这样的:
public String fileToString(File file, Charset charset) {
Scanner fileReader = new Scanner(file, charset);
fileReader.useDelimiter("\\Z"); // \Z means EOF.
String out = fileReader.next();
fileReader.close();
return out;
}
如果您使用 Java 7 或更高版本(您确实应该这样做),请考虑使用 try-with-resources 来使代码更易于阅读。不再有点关闭的东西乱扔东西。但我认为这主要是一种风格选择。
我发布这篇文章主要是为了完成主义,因为如果你需要经常这样做,java.nio.file.Files 中应该有一些东西可以更好地完成这项工作。
我的建议是使用 Files#readAllBytes(Path) 来获取所有字节,并将其馈送到新的 String(byte[] Charset) 以从中获取您可以信任的 String。字符集在你有生之年对你来说是卑鄙的,所以现在要小心这些东西。
其他人已经提供了代码和东西,我不想窃取他们的荣耀。;)
在 Java 7 中,这是我读取 UTF-8 文件的首选选项:
String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");
从 Java 7 开始,JDK 有了新的 API,它提供了许多快捷方式,因此简单的文件操作并不总是需要第三方库。java.nio.file
由于人们仍在对这个答案投赞成票,这里有一个更好的解决方案,在 Java 11 中引入:
String content = Files.readString(path);
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
Java 7 版本
String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);
爪哇 11
String content = Files.readString(Paths.get("readMe.txt"));
使用这个库,它是一行:
String data = IO.from(new File("data.txt")).toString();
评论
您可以尝试 Scanner 和 File 类,几行解决方案
try
{
String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
System.out.println(content);
}
catch(FileNotFoundException e)
{
System.out.println("not found!");
}
此外,如果您的文件恰好在 jar 中,您也可以使用它:
public String fromFileInJar(String path) {
try ( Scanner scanner
= new Scanner(getClass().getResourceAsStream(path))) {
return scanner.useDelimiter("\\A").next();
}
}
例如,如果你的 jar 是/
my.jar/com/some/thing/a.txt
然后你要像这样调用它:
String myTxt = fromFileInJar("/com/com/thing/a.txt");
在一行 (Java 8) 中,假设您有一个 Reader:
String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));
根据 @erickson 的回答,您可以使用:
public String readAll(String fileName) throws IOException {
List<String> lines = Files.readAllLines(new File(fileName).toPath());
return String.join("\n", lines.toArray(new String[lines.size()]));
}
收集了从磁盘或网络中读取文件作为字符串的所有可能方法。
-
static Charset charset = com.google.common.base.Charsets.UTF_8; public static String guava_ServerFile( URL url ) throws IOException { return Resources.toString( url, charset ); } public static String guava_DiskFile( File file ) throws IOException { return Files.toString( file, charset ); }
APACHE - 使用类 IOUtils、FileUtils 的 COMMONS IO
static Charset encoding = org.apache.commons.io.Charsets.UTF_8; public static String commons_IOUtils( URL url ) throws IOException { java.io.InputStream in = url.openStream(); try { return IOUtils.toString( in, encoding ); } finally { IOUtils.closeQuietly(in); } } public static String commons_FileUtils( File file ) throws IOException { return FileUtils.readFileToString( file, encoding ); /*List<String> lines = FileUtils.readLines( fileName, encoding ); return lines.stream().collect( Collectors.joining("\n") );*/ }
使用 Stream API 的 Java 8 BufferReader
public static String streamURL_Buffer( URL url ) throws IOException { java.io.InputStream source = url.openStream(); BufferedReader reader = new BufferedReader( new InputStreamReader( source ) ); //List<String> lines = reader.lines().collect( Collectors.toList() ); return reader.lines().collect( Collectors.joining( System.lineSeparator() ) ); } public static String streamFile_Buffer( File file ) throws IOException { BufferedReader reader = new BufferedReader( new FileReader( file ) ); return reader.lines().collect(Collectors.joining(System.lineSeparator())); }
带有正则表达式的 Scanner 类。这与输入的开头匹配。
\A
static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString(); public static String streamURL_Scanner( URL url ) throws IOException { java.io.InputStream source = url.openStream(); Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A"); return scanner.hasNext() ? scanner.next() : ""; } public static String streamFile_Scanner( File file ) throws IOException { Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A"); return scanner.hasNext() ? scanner.next() : ""; }
Java 7 (
java.nio.file.Files.readAllBytes
)public static String getDiskFile_Java7( File file ) throws IOException { byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() )); return new String( readAllBytes ); }
BufferedReader
用。InputStreamReader
public static String getDiskFile_Lines( File file ) throws IOException { StringBuffer text = new StringBuffer(); FileInputStream fileStream = new FileInputStream( file ); BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) ); for ( String line; (line = br.readLine()) != null; ) text.append( line + System.lineSeparator() ); return text.toString(); }
使用main方法访问上述方法的示例。
public static void main(String[] args) throws IOException {
String fileName = "E:/parametarisation.csv";
File file = new File( fileName );
String fileStream = commons_FileUtils( file );
// guava_DiskFile( file );
// streamFile_Buffer( file );
// getDiskFile_Java7( file );
// getDiskFile_Lines( file );
System.out.println( " File Over Disk : \n"+ fileStream );
try {
String src = "https://code.jquery.com/jquery-3.2.1.js";
URL url = new URL( src );
String urlStream = commons_IOUtils( url );
// guava_ServerFile( url );
// streamURL_Scanner( url );
// streamURL_Buffer( url );
System.out.println( " File Over Network : \n"+ urlStream );
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@see
使用 JDK 8 或更高版本:
不使用外部库
您可以从文件内容创建新的 String 对象(使用包中的类):java.nio.file
public String readStringFromFile(String filePath) throws IOException {
String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
return fileContent;
}
评论
从 JDK 11 开始:
String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8
评论
用户读取文件的所有行。java.nio.Files
public String readFile() throws IOException {
File fileToRead = new File("file path");
List<String> fileLines = Files.readAllLines(fileToRead.toPath());
return StringUtils.join(fileLines, StringUtils.EMPTY);
}
评论
byte[] Files.readAllBytes(file);