如何从文件内容创buildJavastring?

我已经使用了一段时间以下的习语。 这似乎是最广泛的,至less在我访问的网站。

有没有更好的/不同的方式来读取文件到Java中的string?

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

读取文件中的所有文本

这里有一个紧凑的,强大的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); 

在Java 8中, BufferedReader添加了一个新的方法,用lines()来产生一个Stream<String> 。 如果在读取文件时遇到IOException ,则将其包装在UncheckedIOException ,因为Stream不接受抛出检查exception的lambdas。

 try (BufferedReader r = Files.newBufferedReader(path, encoding)) { r.lines().forEach(System.out::println); } 

内存利用率

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

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

为了读取大文件,你需要为你的程序devise一个不同的devise,从一个stream中读取一段文本,处理它,然后移动到下一个,重新使用同一个固定大小的内存块。 这里“大”取决于电脑的规格。 如今,这个门槛可能是很多千兆字节的RAM。 如果您的input“logging”碰巧是单独的行,则使用Stream<String>的第三种方法是执行此操作的一种方法。 (使用BufferedReaderreadLine()方法与此方法相当。)

字符编码

原始文章中的示例中缺less的是字符编码。 有一些特殊情况下,平台默认是你想要的,但它们很less,你应该能够certificate你的select。

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

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

平台默认可从Charset类本身获得:

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

注意:这个答案在很大程度上取代了我的Java 6版本。 Java 7的实用程序安全地简化了代码,而使用映射字节缓冲区的旧答案阻止了从被删除的文件被删除,直到映射的缓冲区被垃圾收集为止。 您可以通过此答案上的“编辑”链接查看旧版本。

Commons FileUtils.readFileToString

 public static String readFileToString(File file) throws IOException 

使用VM的默认编码将文件的内容读入string。 该文件始终closures。

参数:

  • file – 要读取的文件不能为空

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

抛出: IOException – 如果发生I / O错误

从:Commons IO 1.3.1

该类使用(间接)的代码是:

Apache许可证2.0下的IOUtils.java 。

 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使用的非常相似。

从这个页面可以看出一个非常精简

 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 

如果你想设置字符集

如果您正在寻找不涉及第三方库(如Commons I / O )的替代scheme,则可以使用Scanner类:

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

番石榴有一个类似于来自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); 

奥斯卡·雷耶斯编辑

这是引用库中的(简化)底层代码:

 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包中的Files , CharStreams , ByteSource和CharSource类。

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

如果你需要一个string处理(并行处理),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下载页面下载这些sample/lambda/BulkDataOperations

另一个class轮的例子

 String out = String.join("\n", Files.readAllLines(Paths.get("file.txt"))); 

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

这是一个不这样做的替代scheme,哪个(IMO)比NIO代码更容易理解(尽pipe它仍然使用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(); } } 
 String content = new String(Files.readAllBytes(Paths.get("readMe.txt"))); 

因为Java 7你可以这样做。

如果是文本文件,为什么不使用apache commons-io ?

它有以下方法

 public static String readFileToString(File file) throws IOException 

如果你想把这些行作为列表使用

 public static List<String> readLines(File file) throws IOException 

以二进制forms读取文件并在最后进行转换

 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在所有方面都尝试着非常普遍和灵活。 因此,在脚本语言中相对简单的东西(你的代码将被replace为python中的“ open(file).read() ”)要复杂得多。 除了使用外部库(比如Willi aus Rohr提到的)之外,似乎还没有更简单的方法。 您的select:

  • 使用外部库。
  • 将此代码复制到您的所有项目中。
  • 创build您自己的迷你库,其中包含您经常使用的function。

你最好的select可能是第二个,因为它的依赖性最小。

一线解决scheme

 String content = new String(Files.readAllBytes(Paths.get("d://test.txt"))); 

在同一主题上有一个变体,它使用for循环而不是while循环来限制行variables的范围。 是否“更好”是个人品味的问题。

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

对于Java 7,这是我读取UTF-8文件的首选选项:

 String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8"); 

自Java 7以来,JDK具有新的java.nio.file API,它提供了许多快捷方式,因此对于简单的文件操作,并不总是需要第三方库。

 public static String slurp (final File file) throws IOException { StringBuilder result = new StringBuilder(); try { BufferedReader reader = new BufferedReader(new FileReader(file)); 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(); } 

如果您无法访问文件,请执行以下操作:

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

使用来自Apache commons-io的 IOUtils和StringWriter的灵活解决scheme:

 Reader input = new FileReader(); StringWriter output = new StringWriter(); try { IOUtils.copy(input, output); } finally { input.close(); } String fileContents = output.toString(); 

它适用于任何阅读器或inputstream(而不仅仅是文件),例如从URL读取时。

请注意,在使用fileInputStream.available() ,返回的整数不必表示实际的文件大小,而是系统应能够从stream中读取而不阻塞IO的字节量。 一个安全和简单的方法可能是这样的

 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这样的多字节字符编码。

这个使用了RandomAccessFile.readFully方法,它似乎可以从JDK 1.0中获得!

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

扫描仪后Ctrl + F后,我认为扫描仪解决scheme也应列出。 在最简单的阅读时尚是这样的:

 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或更新版本(而且您确实应该)考虑使用试用资源来使代码更易于阅读。 没有更多的点closures东西乱扔垃圾的一切。 但这大多是一种文体select。

我发布这主要是为了完成,因为如果你需要做很多,应该在java.nio.file.Files中的东西,应该做的更好的工作。

我的build议是使用Files#readAllBytes(Path)来获取所有的字节,并将其提供给新的String(byte [] Charset)以获得一个你可以信任的string。 在你的一生中,字符集对你来说意味着什么,所以要小心这个东西。

其他人已经提供了代码和东西,我不想窃取他们的荣耀。 ;)

使用这个库 ,它是一条线:

 String data = IO.from(new File("data.txt")).toString(); 

您可以尝试Scanner和File类,几行解决scheme

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

path应该以/开头,例如,如果你的jar是

 my.jar/com/some/thing/a.txt 

然后你想像这样调用它:

 String myTxt = fromFileInJar("/com/com/thing/a.txt"); 

我还不能评论其他条目,所以我只是把它留在这里。

这里最好的答案之一( 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(); } } 

仍然有一个缺陷。 它总是把新的string放在string的末尾,这可能会导致一些奇怪的错误。 我的build议是将其更改为:

  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)中,假设你有一个Reader:

 String sMessage = String.join("\n", reader.lines().collect(Collectors.toList())); 

在java 8中,有一个新的类

java.util.stream.Stream

stream表示一系列元素,并支持对这些元素进行计算的不同types的操作

阅读更多关于它:

Oracle文档

这里是一个例子:

 import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.stream.Stream; public Class ReadFile{ public static String readFile(String filePath) { StringBuilder stringBuilder = new StringBuilder(); String ls = System.getProperty("line.separator"); try { try (Stream<String> lines = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8)) { for (String line : (Iterable<String>) lines::iterator) { stringBuilder.append(line); stringBuilder.append(ls); } } } catch (Exception e) { e.printStackTrace(); } return stringBuilder.toString(); } } 

使用代码:

 File file = new File("input.txt"); BufferedInputStream bin = new BufferedInputStream(new FileInputStream( file)); byte[] buffer = new byte[(int) file.length()]; bin.read(buffer); String fileStr = new String(buffer); 

fileStr在String中包含输出。