How do I create a Java string from the contents of a file?
我用下面这个成语已经有一段时间了。这似乎是最广泛的传播,至少在我访问过的网站上。
在Java中读取文件到字符串中有更好的方法吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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的一个紧凑、健壮的习惯用法,它包含在一个实用工具中:
1 2 3 4 5 6 | static String readFile(String path, Charset encoding) throws IOException { byte[] encoded = Files.readAllBytes(Paths.get(path)); return new String(encoded, encoding); } |
从文件中读取文本行
Java 7增加了一种方便的方法来读取文件作为文本行,表示为EDCOX1(2)。这种方法是"有损的",因为线路分隔符是从每一条线路的末端剥离出来的。
1 | List<String> lines = Files.readAllLines(Paths.get(path), encoding); |
Java 8添加了EDCOX1×3的方法来产生EDCOX1×4。同样,这种方法也是有损的,因为行分隔符被剥离了。如果在读取文件时遇到
1 2 3 |
这个
如果您使用的是文件以外的源,则可以在
第一种保留换行符的方法可以临时需要文件大小的几倍内存,因为在很短的时间内,原始文件内容(字节数组)和解码字符(每个字符都是16位,即使在文件中编码为8位)同时驻留在内存中。应用于您知道相对于可用内存较小的文件是最安全的。
第二种方法是读取行,通常内存效率更高,因为用于解码的输入字节缓冲区不需要包含整个文件。但是,它仍然不适用于相对于可用内存非常大的文件。
对于读取大型文件,您需要为您的程序设计一种不同的设计,即从流中读取文本块,对其进行处理,然后转到下一个,重用相同的固定大小的内存块。这里,"大"取决于计算机规格。现在,这个阈值可能是许多千兆字节的RAM。第三种方法,使用
原始日志中样本中缺少的一件事是字符编码。有些特殊情况下,平台默认值是您想要的,但它们很少,您应该能够证明自己的选择是正确的。
EDCOX1×17类定义了所有Java运行时所需的编码的常数:
1 |
平台默认值可从
1 |
注意:这个答案在很大程度上取代了我的Java 6版本。Java 7的实用程序安全地简化了代码,而使用映射字节缓冲区的旧答案阻止了被读取的文件被删除,直到映射的缓冲区被垃圾收集。您可以通过此答案上的"已编辑"链接查看旧版本。
公地
1
2Reads the contents of a file into a String using the default encoding
for the VM. The file is always closed.Parameters:
file - the file to read, must not be nullReturns:
the file contents, never nullThrows:
-IOException - in case of an I/O errorSince:
Commons IO 1.3.1
该类(间接)使用的代码是:
ioutils.java,根据Apache许可证2.0。
1 2 3 4 5 6 7 8 9 10 11 | 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使用的。
从本页中可以看出一个非常精简的解决方案:
1 2 3 |
或
1 2 3 |
如果你想设置字符集
1 2 3 4 |
自Java 7以来,你可以这样做。
如果您正在寻找不涉及第三方库的替代方案(例如,Commons I/O),则可以使用scanner类:
1 2 3 4 5 6 7 8 9 10 11 12 | 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的方法类似于Willi Aus Rohr提到的Commons IOutils方法:
1 2 3 4 5 6 |
由Oscar Reyes编辑
这是引用库上的(简化)基础代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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包中的类文件、charstreams、bytesource和charsource。
1 | import java.nio.file.Files; |
……
1 2 3 4 5 6 7 8 9 10 11 12 | 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代码更容易理解(imo)(尽管它仍然使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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具有大流API。
1 2 3 4 5 |
在JDK示例EDCOX1(3)中,可以从Oracle Java SE 8下载页面下载更多的示例。
另一个单内衬示例
已收集从磁盘或网络以字符串形式读取文件的所有可能方法。
guava:google使用类
Resources ,Files 1
2
3
4
5
6
7static 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 );
}
使用ioutils、fileutils类的apache-commons IO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15static 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("
") );*/
}
使用流API的Java 8缓冲读取器
1
2
3
4
5
6
7
8
9
10public 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()));
}
带regex
\A 的scanner类。与输入的开头匹配。1
2
3
4
5
6
7
8
9
10static 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(EDOCX1,4)
1
2
3
4public static String getDiskFile_Java7( File file ) throws IOException {
byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
return new String( readAllBytes );
}
使用
InputStreamReader 的BufferedReader 。1
2
3
4
5
6
7
8public 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();
}
示例与主方法访问上述方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 : "+ 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 : "+ urlStream ); } catch (MalformedURLException e) { e.printStackTrace(); } } |
参见
- 将输入流转换为字符串的方法
如果是文本文件,为什么不使用ApacheCommons IO?
它有以下方法
1 |
如果要将行作为列表,请使用
1 |
自JDK 11以来:
1 2 3 4 |
以二进制形式读取文件并在末尾转换
1 2 3 4 5 6 7 8 9 10 11 12 | 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文件的首选选项:
自Java 7以来,JDK具有新的EDCOX1×5的API,它提供了许多快捷方式,因此对于简单的文件操作并不总是需要第三方库。
Java试图在它所做的一切中都是极其通用和灵活的。因此,在脚本语言中相对简单的一些东西(您的代码将在Python中替换为"
- 使用外部库。
- 将此代码复制到所有项目中。
- 创建您自己的迷你库,其中包含您经常使用的函数。
你最好的选择可能是第二个,因为它的依赖性最小。
使用JDK 8或更高版本:
未使用外部库
您可以从文件内容(使用
1 2 3 4 | public String readStringFromFile(String filePath) throws IOException { String fileContent = new String(Files.readAllBytes(Paths.get(filePath))); return fileContent; } |
同一主题上有一个变体,它使用for循环(而不是while循环)来限制行变量的范围。它是否"更好"是个人品味的问题。
1 2 3 4 | for(String line = reader.readLine(); line != null; line = reader.readLine()) { stringBuilder.append(line); stringBuilder.append(ls); } |
如果您没有访问
1 2 3 4 5 6 7 8 9 | 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:
1 2 3 4 5 6 7 8 | Reader input = new FileReader(); StringWriter output = new StringWriter(); try { IOUtils.copy(input, output); } finally { input.close(); } String fileContents = output.toString(); |
它与任何读卡器或输入流(不只是文件)一起工作,例如从URL读取时。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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(); } |
注意,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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这样的多字节字符编码。
用户
1 2 3 4 5 | public String readFile() throws IOException { File fileToRead = new File("file path"); List<String> fileLines = Files.readAllLines(fileToRead.toPath()); return StringUtils.join(fileLines, StringUtils.EMPTY); } |
这一个使用了方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 } } } |
你可以试试扫描器和文件类,几行解决方案
1 2 3 4 5 6 7 8 9 | try { String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next(); System.out.println(content); } catch(FileNotFoundException e) { System.out.println("not found!"); } |
根据@erickson的回答,您可以使用:
1 2 3 4 5 |
在一行(Java 8)中,假设您有一个读取器:
另外,如果您的文件正好在JAR中,您也可以使用它:
1 2 3 4 5 6 |
例如,如果jar是
1 | my.jar/com/some/thing/a.txt |
然后您想这样调用它:
1 |
使用此库,它是一行:
在扫描器完成ctrl+f'ing之后,我认为扫描器解决方案也应该列出。最容易阅读的方式是这样:
1 2 3 4 5 6 7 |
如果您使用Java 7或更新器(并且您确实应该)考虑使用尝试资源来使代码更易于阅读。不要再到处乱扔东西了。但我认为,这主要是一种风格选择。
我发布这篇文章主要是为了完成主义,因为如果您需要做很多工作,那么java.nio.file.files中应该有更好的工作。
我的建议是使用文件readallbytes(path)来获取所有字节,并将其馈送到新的字符串(byte[]charset)中以获取您可以信任的字符串。字符集在你的一生中对你很重要,所以现在要小心这些东西。
其他人给了他们代码和东西,我不想窃取他们的荣耀。;)
我还不能评论其他条目,所以我将把它留在这里。
这里的最佳答案之一(https://stackoverflow.com/a/326448/1521167):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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(); } } |
还有一个缺陷。它总是将新行字符放在字符串的末尾,这可能会导致一些weirds错误。我的建议是将其更改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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(); } } |
使用代码:
1 2 3 4 5 6 | 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包含字符串形式的输出。
在Java 8中,有一个新类
java.util.stream.Stream
流表示元素序列,并支持对这些元素执行计算的不同类型的操作。
了解更多信息:
Oracle文档
这里有一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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(); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.stream.Collectors; /** * A simple example program that reads a text file into a String using Files.lines and stream. */ public class ReadTextFileExample { public static void main(String[] args) throws IOException { String contents = Files.lines(Paths.get("c:\\temp\\testfile.txt")).collect(Collectors.joining(" ")); System.out.println(contents); } } |