java - 如何创建一个Java String从一个文件的内容?

  显示原文与译文双语对照的内容

我已经用了一段时间了。 这似乎是最 wide-spread,至少在我访问过的网站中。

是否有人有更好的/不同的方式来将文件读入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");

 while( ( line = reader.readLine() )!= null ) {
 stringBuilder.append( line );
 stringBuilder.append( ls );
 }

 return stringBuilder.toString();
}

时间:

从文件读取所有文本

下面是一个用于 Java 7的简洁,健壮的习惯用法,它打包在一个工具方法中:


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);

内存利用率

第一种方法,保留换行符,可以暂时要求内存的大小,因为短时间内,原始文件的内容( 字节数组) 和解码字符的( 每一个都是 16位,即使编码为 8位) 驻留在内存中。 最安全的方法是应用到相对于可用内存小的文件。

第二种方法,读取行,通常是更高的内存效率,因为用于解码的输入字节缓冲区不需要包含整个文件。 但是,它仍然不适用于相对于可用内存较大的文件。

对于读取大文件,你需要一个不同的程序设计,一个从流中读取文本块,处理它,然后继续到下一步,重用相同的fixed-sized内存块。 这里,"大"依赖于计算机规格。 现在,这个阈值可能有gigabytes字节的内存。

字符编码

在原始日志中的示例中缺少的一件事是字符编码。 在某些特殊情况下,平台默认是你想要的,但是它们很少,你应该能够证明你的选择。

StandardCharsets 类为所有Java运行时所需的编码定义一些常量:


String content = readFile("test.txt", StandardCharsets.UTF_8);

平台默认值可以从中获得 Charset本身:


String content = readFile("test.txt", Charset.defaultCharset());


注意:这个答案基本上取代了我的Java 6版本。 Java 7的实用工具安全地简化了代码和旧的应答,它使用了映射的字节缓冲区,防止读取被读取的文件,直到映射缓冲区被垃圾回收。 你可以通过这里答案的"已经编辑"链接查看旧版本。

共用 FileUtils.readFileToString:


public static String readFileToString(File file)
 throws IOException

将文件的内容使用虚拟机的默认编码读入一个字符串。 文件总是关闭的。

参数:

  • file - 要读取的文件,不得为空

返回:
文件内容,从不为空

抛出:- IOException - 发生i/o 错误时抛出

自以下:
共用 IO 1.3.1

被奥斯卡瑞斯 编辑

我已经找到了( 间接) 使用的代码:

IOUtils.javaApache许可证下 2.0


public static long copyLarge(InputStream input, OutputStream output)
 throws IOException {
 byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
 long count = 0;
 int n = 0;
 while (-1!= (n = input.read(buffer))) {
 output.write(buffer, 0, n);
 count += n;
 }
 return count;
}

Ritche_W使用的非常相似

中,这里页面 one-line解决方案:


 String text = new Scanner( new File("poem.txt") ).useDelimiter("A").next();

或者


String text = new Scanner( new File("poem.txt"),"UTF-8" ).useDelimiter("A").next();

如果你想设置字符集

如果你正在寻找一个不涉及 3 rd库库的替代品( 例如。 共用版本),你可以使用扫描仪


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();
 }
}

Guava 有一个类似于IOUtils的方法,其中提到了Willi语句:


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

//...

String text = Files.toString(new File(path), Charsets.UTF_8);

被奥斯卡瑞斯 编辑

这是引用库中的( 简化) 基础代码:


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 版本的源代码不匹配。 在 com.google.common.io package,为当前源,请参见 的类文件,CharStreamsByteSourceCharSource.


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"";
 }

代码将正常化换行符,这可能是你真正想要做的,也可能不是。

这里是另一种方法,并不会这样和新系统是比的NIO代码( 尽管它仍然使用 java.nio. 字符集。字符集): ( IMO ) 能够更加容易理解


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();
 } 
}

以二进制形式读取文件并在结尾处转换


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试图在所有方面都非常通用和灵活。 因此,在脚本语言( 你的代码将被替换为" open(file).read()"在 python 中) 中相对简单的东西会更加复杂。 除了使用外部库( 就像 Willi Rohr 提到的那样) 之外,似乎没有更短的方法。 你的选项:

  • 使用外部库。
  • 将这里代码复制到所有项目中。
  • 创建包含你经常使用的函数的mini-library 。

你最好的选择可能是 2,因为它的依赖性最小。

...