How do I create a Java string from the contents of a file?
I've been using the idiom below for some time now. And it seems to be the most wide-spread, at least on the sites I've visited.
Is there a better/different way to read a file into a string in 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();
}
}
Read all text from a file
Here's a compact, robust idiom for Java 7, wrapped up in a utility method:
static String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}
Read lines of text from a file
Java 7 added a convenience method to read a file as lines of text, represented as a List<String>
. This approach is "lossy" because the line separators are stripped from the end of each line.
List<String> lines = Files.readAllLines(Paths.get(path), encoding);
In Java 8, BufferedReader
added a new method, lines()
to produce a Stream<String>
. If an IOException
is encountered while reading the file, it is wrapped in an UncheckedIOException
, since Stream
doesn't accept lambdas that throw checked exceptions.
try (BufferedReader r = Files.newBufferedReader(path, encoding)) {
r.lines().forEach(System.out::println);
}
There is also a Files.lines()
method which does something very similar, returning the Stream<String>
directly. But I don't like it. The Stream
needs a close()
call; this is poorly documented on the API, and I suspect many people don't even notice Stream
has a close()
method. So your code would look very similar, like this:
try (Stream<String> lines = Files.lines(path, encoding)) {
lines.forEach(System.out::println);
}
The difference is that you have a Stream
assigned to a variable, and I try avoid that as a practice so that I don't accidentally try to invoke the stream twice.
Memory utilization
The first method, that preserves line breaks, can temporarily require memory several times the size of the file, because for a short time the raw file contents (a byte array), and the decoded characters (each of which is 16 bits even if encoded as 8 bits in the file) reside in memory at once. It is safest to apply to files that you know to be small relative to the available memory.
The second method, reading lines, is usually more memory efficient, because the input byte buffer for decoding doesn't need to contain the entire file. However, it's still not suitable for files that are very large relative to available memory.
For reading large files, you need a different design for your program, one that reads a chunk of text from a stream, processes it, and then moves on to the next, reusing the same fixed-sized memory block. Here, "large" depends on the computer specs. Nowadays, this threshold might be many gigabytes of RAM. The third method, using a Stream<String>
is one way to do this, if your input "records" happen to be individual lines. (Using the readLine()
method of BufferedReader
is the procedural equivalent to this approach.)
Character encoding
One thing that is missing from the sample in the original post is the character encoding. There are some special cases where the platform default is what you want, but they are rare, and you should be able justify your choice.
The StandardCharsets
class define some constants for the encodings required of all Java runtimes:
String content = readFile("test.txt", StandardCharsets.UTF_8);
The platform default is available from the Charset
class itself:
String content = readFile("test.txt", Charset.defaultCharset());
Note: This answer largely replaces my Java 6 version. The utility of Java 7 safely simplifies the code, and the old answer, which used a mapped byte buffer, prevented the file that was read from being deleted until the mapped buffer was garbage collected. You can view the old version via the "edited" link on this answer.
Commons FileUtils.readFileToString
:
public static String readFileToString(File file)
throws IOException
Reads 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 null Returns: the file contents, never null
Throws: - IOException
- in case of an I/O error
Since: Commons IO 1.3.1
The code used (indirectly) by that class is:
IOUtils.java under Apache Licence 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;
}
It is very similar to the one used by Ritche_W.
From this page a very lean solution:
Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("A").next();
scanner.close(); // Put this call in a finally block
or
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
If you want to set the charset
链接地址: http://www.djcxy.com/p/5944.html上一篇: 从输入流过滤\ n字符
下一篇: 如何从文件内容创建Java字符串?