如何从文件内容创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>
的第三种方法是执行此操作的一种方法。 (使用BufferedReader
的readLine()
方法与此方法相当。)
字符编码
原始文章中的示例中缺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中包含输出。