我一直在使用下面的成语一段时间了.它似乎是最广泛的,至少在我访问过的网站上.
是否有更好/不同的方式将文件读入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(); } }
erickson.. 1467
这是Java 7的一个紧凑,健壮的习惯用法,包含在一个实用程序方法中:
String content = Files.readString(path, StandardCharsets.US_ASCII);
Java 7添加了一种方便的方法来将文件读取为文本行,表示为String
.这种方法是"有损"的,因为行分隔符从每行的末尾剥离.
static String readFile(String path, Charset encoding) throws IOException { byte[] encoded = Files.readAllBytes(Paths.get(path)); return new String(encoded, encoding); }
在Java 8中,List
添加了一个新方法,Files.lines()
以生成一个Stream
.如果IOException
在读取文件时遇到a,则将其包装在一个中UncheckedIOException
,因为Stream
不接受抛出已检查异常的lambdas.
Listlines = Files.readAllLines(Paths.get(path), encoding);
还有一种Stream
方法可以做一些非常相似的事情,close()
直接返回.但我不喜欢它.在Stream
需要close()
调用; 这在API上记录很少,我怀疑很多人甚至没有注意到lines()
有一种BufferedReader
方法.所以你的代码看起来非常相似,如下所示:
try (Streamlines = Files.lines(path, encoding)) { lines.forEach(System.out::println); }
区别在于你已经Stream
分配了一个变量,我尝试避免这种做法,以便我不小心尝试两次调用流.
第一种保留换行符的方法可以暂时需要几倍于文件大小的内存,因为短时间内原始文件内容(一个字节数组)和解码后的字符(即使编码也是16位)因为文件中的8位)一次驻留在内存中.最安全的方法是应用于您知道相对于可用内存较小的文件.
读取行的第二种方法通常更有效,因为用于解码的输入字节缓冲区不需要包含整个文件.但是,它仍然不适合相对于可用内存非常大的文件.
对于读取大型文件,您需要为程序设计一个不同的设计,一个从流中读取一块文本,处理它,然后继续下一个,重用相同的固定大小的内存块.这里,"大"取决于计算机规格.如今,这个阈值可能是几千兆字节的RAM.readLine()
如果您的输入"记录"恰好是单独的行,则使用a的第三种方法是这样做的一种方法.(使用BufferedReader
方法StandardCharsets
是程序等同于这种方法.)
原始帖子中的示例中缺少的一件事是字符编码.在某些特殊情况下,平台默认值是您想要的,但它们很少见,您应该能够证明您的选择.
在Charset
类中定义的所有Java运行时所需要的编码的一些常量:
String content = readFile("test.txt", StandardCharsets.UTF_8);
该平台默认可从该String
类本身:
String content = readFile("test.txt", Charset.defaultCharset());
注意:这个答案很大程度上取代了我的Java 6版本.Java 7的实用程序安全地简化了代码,使用映射字节缓冲区的旧答案阻止了读取的文件被删除,直到映射的缓冲区被垃圾收集.您可以通过此答案中的"已编辑"链接查看旧版本.
这是Java 7的一个紧凑,健壮的习惯用法,包含在一个实用程序方法中:
String content = Files.readString(path, StandardCharsets.US_ASCII);
Java 7添加了一种方便的方法来将文件读取为文本行,表示为String
.这种方法是"有损"的,因为行分隔符从每行的末尾剥离.
static String readFile(String path, Charset encoding) throws IOException { byte[] encoded = Files.readAllBytes(Paths.get(path)); return new String(encoded, encoding); }
在Java 8中,List
添加了一个新方法,Files.lines()
以生成一个Stream
.如果IOException
在读取文件时遇到a,则将其包装在一个中UncheckedIOException
,因为Stream
不接受抛出已检查异常的lambdas.
Listlines = Files.readAllLines(Paths.get(path), encoding);
还有一种Stream
方法可以做一些非常相似的事情,close()
直接返回.但我不喜欢它.在Stream
需要close()
调用; 这在API上记录很少,我怀疑很多人甚至没有注意到lines()
有一种BufferedReader
方法.所以你的代码看起来非常相似,如下所示:
try (Streamlines = Files.lines(path, encoding)) { lines.forEach(System.out::println); }
区别在于你已经Stream
分配了一个变量,我尝试避免这种做法,以便我不小心尝试两次调用流.
第一种保留换行符的方法可以暂时需要几倍于文件大小的内存,因为短时间内原始文件内容(一个字节数组)和解码后的字符(即使编码也是16位)因为文件中的8位)一次驻留在内存中.最安全的方法是应用于您知道相对于可用内存较小的文件.
读取行的第二种方法通常更有效,因为用于解码的输入字节缓冲区不需要包含整个文件.但是,它仍然不适合相对于可用内存非常大的文件.
对于读取大型文件,您需要为程序设计一个不同的设计,一个从流中读取一块文本,处理它,然后继续下一个,重用相同的固定大小的内存块.这里,"大"取决于计算机规格.如今,这个阈值可能是几千兆字节的RAM.readLine()
如果您的输入"记录"恰好是单独的行,则使用a的第三种方法是这样做的一种方法.(使用BufferedReader
方法StandardCharsets
是程序等同于这种方法.)
原始帖子中的示例中缺少的一件事是字符编码.在某些特殊情况下,平台默认值是您想要的,但它们很少见,您应该能够证明您的选择.
在Charset
类中定义的所有Java运行时所需要的编码的一些常量:
String content = readFile("test.txt", StandardCharsets.UTF_8);
该平台默认可从该String
类本身:
String content = readFile("test.txt", Charset.defaultCharset());
注意:这个答案很大程度上取代了我的Java 6版本.Java 7的实用程序安全地简化了代码,使用映射字节缓冲区的旧答案阻止了读取的文件被删除,直到映射的缓冲区被垃圾收集.您可以通过此答案中的"已编辑"链接查看旧版本.
下议院org.apache.commons.io.FileUtils.readFileToString()
:
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); }
使用VM的默认编码将文件内容读入String.该文件始终关闭.
参数:
File
- 要读取的文件,不能为null
返回:文件内容,永远不为null
抛出: -
String
- 如果发生I/O错误自:Commons IO 1.3.1
该类(间接)使用的代码是:
Apache License 2.0下的IOUtils.java.
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);
}
它与Ritche_W使用的非常相似.
从这个页面非常精简的解决方案:
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
如果要设置charset
import java.nio.file.Files; import java.nio.file.Paths; String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), "UTF-8");
从java 7开始,你可以这样做.
如果您正在寻找不涉及第三方库(例如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(); } }
Guava有一种类似于Commons IOUtils的方法,Willi aus Rohr提到:
import com.google.common.base.Charsets; import com.google.common.io.Files; // ... String text = Files.toString(new File(path), Charsets.UTF_8);
由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版本的源代码不符.对于电流源,看到类文件,CharStreams,ByteSource和CharSource在com.google.common.io包.
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 ""; }
该代码将规范化换行符,这可能是也可能不是您真正想要做的.
这是一个不能做到这一点的替代方案,而且(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(); } }
如果您需要字符串处理(并行处理),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示例中提供了更多示例sample/lambda/BulkDataOperations
,可以从Oracle Java SE 8下载页面下载
另一个班轮示例
String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));
收集了从磁盘或网络读取文件为字符串的所有可能方法.
番石榴:谷歌使用课程Resources
,Files
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 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 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()));
}
具有正则表达式的扫描仪类\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();
}
}
@看到
将InputStream转换为String的方法
如果是文本文件,为什么不使用apache commons-io?
它有以下方法
public static String readFileToString(File file) throws IOException
如果要将行作为列表使用
public static ListreadLines(File file) throws IOException
从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
将文件读取为二进制文件并在结尾处进行转换
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(); } }
使用Java 7,这是我读取UTF-8文件的首选选项:
String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");
从Java 7开始,JDK就拥有了新的java.nio.file
API,它提供了许多快捷方式,因此简单的文件操作并不总是需要第三方库.
Java试图在其所有方面都非常通用和灵活.因此,在脚本语言中相对简单的东西(您的代码将open(file).read()
在python中替换为" ")要复杂得多.除了使用外部库(如Willi aus Rohr提到的)之外,似乎没有任何更短的方法.你的选择:
使用外部库.
将此代码复制到您的所有项目中.
创建自己的迷你库,其中包含您经常使用的功能.
你最好的选择可能是第二个,因为它的依赖性最小.
没有使用外部库
您可以从文件内容创建一个新的String对象(使用java.nio.file
包中的类):
public String readStringFromFile(String filePath) throws IOException { String fileContent = new String(Files.readAllBytes(Paths.get(filePath))); return fileContent; }
在同一主题上有一个变体,它使用for循环而不是while循环来限制行变量的范围.它是否"更好"是个人品味的问题.
for(String line = reader.readLine(); line != null; line = reader.readLine()) { stringBuilder.append(line); stringBuilder.append(ls); }
如果您无权访问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); }