读文件
http://www.baeldung.com/java-read-file
Java – Read from File
1. Overview
In this tutorial we’ll explore different ways to read from a File in Java; we’ll make use ofBufferedReader, Scanner, StreamTokenizer, DataInputStream, SequenceInputStream andFileChannel.
Then, we will discuss how to read a UTF-8 encoded file and how to create String from contents of a file.
Finally, we’ll explore the new techniques to read from file in Java 7.
This article is part of the “Java – Back to Basic” series here on Baeldung.
2. Read with BufferedReader
Let’s start with a simple way to read from file using BufferedReader; the file itself contains:
1
|
Hello world
|
The following code reads from the file using BufferedReader:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
whenReadWithBufferedReader_thenCorrect()
throws
IOException {
String expected_value =
"Hello world"
;
String file =
"src/test/resources/test_read.txt"
;
BufferedReader reader =
new
BufferedReader(
new
FileReader(file));
String currentLine = reader.readLine();
reader.close();
assertEquals(expected_value, currentLine);
}
|
Note that readLine() will return null when the end of the file is reached.
3. Read with Scanner
Next, let’s use a Scanner to read from the File – the file contains:
1
|
Hello world 1
|
We’ll use a simple whitespace as the delimiter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Test
public
void
whenReadWithScanner_thenCorrect()
throws
IOException {
String file =
"src/test/resources/test_read.txt"
;
Scanner scanner =
new
Scanner(
new
File(file));
scanner.useDelimiter(
" "
);
assertTrue(scanner.hasNext());
assertEquals(
"Hello"
, scanner.next());
assertEquals(
"world"
, scanner.next());
assertEquals(
1
, scanner.nextInt());
scanner.close();
}
|
Note that the default delimiter is the whitespace, but multiple delimiters can be used with aScanner.
4. Read with StreamTokenizer
Next, let’s read a text file into tokens using a StreamTokenizer.
The way the tokenizer works is – first, we need to figure out what the next token is – String or number; we do that by looking at the tokenizer.ttype field.
Then, we’ll read the actual token based on this type:
- tokenizer.nval – if the type was a number
- tokenizer.sval – if the type was a String
The file simply contains:
1
|
Hello 1
|
The following code reads from the file both the String and the number:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@Test
public
void
whenReadWithStreamTokenizer_thenCorrectTokens()
throws
IOException {
String file =
"src/test/resources/test_read.txt"
;
FileReader reader =
new
FileReader(file);
StreamTokenizer tokenizer =
new
StreamTokenizer(reader);
// token 1
tokenizer.nextToken();
assertEquals(StreamTokenizer.TT_WORD, tokenizer.ttype);
assertEquals(
"Hello"
, tokenizer.sval);
// token 2
tokenizer.nextToken();
assertEquals(StreamTokenizer.TT_NUMBER, tokenizer.ttype);
assertEquals(
1
, tokenizer.nval,
0.0000001
);
// token 3
tokenizer.nextToken();
assertEquals(StreamTokenizer.TT_EOF, tokenizer.ttype);
reader.close();
}
|
Note how the end of file token is used at the end.
5. Read with DataInputStream
We can use DataInputStream to read binary or primitive data type from file.
Let’s start with the actual file itself:
1
|
Hello
|
The following test reads the file using a DataInputStream:
1
2
3
4
5
6
7
8
9
10
11
|
@Test
public
void
whenReadWithDataInputStream_thenCorrect()
throws
IOException {
String expectedValue =
"Hello"
;
String file =
"src/test/resources/test_read.txt"
;
DataInputStream reader =
new
DataInputStream(
new
FileInputStream(file));
String result = reader.readUTF();
reader.close();
assertEquals(expectedValue, result);
}
|
6. Read with SequenceInputStream
Now, let’s look at how to concatenate two input streams into one usingSequenceInputStream; the 2 input files will simply contain:
1
|
2000
|
and:
1
|
5000
|
Let’s now use a SequenceInputStream to read the two files and merge them into one:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Test
public
void
whenReadingTwoFilesWithSequenceInputStream_thenCorrect()
throws
IOException {
int
expectedValue1 =
2000
;
int
expectedValue2 =
5000
;
String file1 =
"src/test/resources/test_read1.txt"
;
String file2 =
"src/test/resources/test_read2.txt"
;
FileInputStream stream1 =
new
FileInputStream(file1);
FileInputStream stream2 =
new
FileInputStream(file2);
SequenceInputStream sequence =
new
SequenceInputStream(stream1, stream2);
DataInputStream reader =
new
DataInputStream(sequence);
assertEquals(expectedValue1, reader.readInt());
assertEquals(expectedValue2, reader.readInt());
reader.close();
stream2.close();
}
|
7. Read with FileChannel
If we are reading a large file, FileChannel can be faster than standard IO.
The contents of the file:
1
|
Hello world
|
The following code reads data bytes from the file using FileChannel and RandomAccessFile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
@Test
public
void
whenReadWithFileChannel_thenCorrect()
throws
IOException {
String expected_value =
"Hello world"
;
String file =
"src/test/resources/test_read.txt"
;
RandomAccessFile reader =
new
RandomAccessFile(file,
"r"
);
FileChannel channel = reader.getChannel();
int
bufferSize =
1024
;
if
(bufferSize > channel.size()) {
bufferSize = (
int
) channel.size();
}
ByteBuffer buff = ByteBuffer.allocate(bufferSize);
channel.read(buff);
buff.flip();
assertEquals(expected_value,
new
String(buff.array()));
channel.close();
reader.close();
}
|
8. Read UTF-8 encoded file
Now, let’s see how to read a UTF-8 encoded file using BufferedReader:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
whenReadUTFEncodedFile_thenCorrect()
throws
IOException {
String expected_value =
"青空"
;
String file =
"src/test/resources/test_read.txt"
;
BufferedReader reader =
new
BufferedReader
(
new
InputStreamReader(
new
FileInputStream(file),
"UTF-8"
));
String currentLine = reader.readLine();
reader.close();
assertEquals(expected_value, currentLine);
}
|
9. Read a file into a String
We can make good use of StringBuilder to read the entire contents of a file into a String. Let’s start with the file:
1
2
3
|
Hello world
Test line
|
The following code append data read from the file into a StringBuilder line by line:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Test
public
void
whenReadFileContentsIntoString_thenCorrect()
throws
IOException {
String expected_value =
"Hello world n Test line n"
;
String file =
"src/test/resources/test_read.txt"
;
BufferedReader reader =
new
BufferedReader(
new
FileReader(file));
StringBuilder builder =
new
StringBuilder();
String currentLine = reader.readLine();
while
(currentLine !=
null
) {
builder.append(currentLine);
builder.append(
"n"
);
currentLine = reader.readLine();
}
reader.close();
assertEquals(expected_value, builder.toString());
}
|
10. Read from File using Java 7
Java 7 introduces a new way of working with files and the filesystem – let’s make use of that to read files.
10.1. Read a Small File with Java 7
The file contents:
1
|
Hello world
|
The following code shows how to read small file using the new Files class:
1
2
3
4
5
6
7
8
9
10
|
@Test
public
void
whenReadSmallFileJava7_thenCorrect()
throws
IOException {
String expected_value =
"Hello world"
;
Path path = Paths.get(
"src/test/resources/test_read.txt"
);
String read = Files.readAllLines(path).get(
0
);
assertEquals(expected_value, read);
}
|
Note that you can use the readAllBytes() method as well if you need binary data.
10.2. Read a Large File with Java 7
If we want to read a large file with Files class, we can use the BufferedReader.
The file contents:
1
|
Hello world
|
The following code reads the file using the new Files class and BufferedReader:
1
2
3
4
5
6
7
8
9
10
11
|
@Test
public
void
whenReadLargeFileJava7_thenCorrect()
throws
IOException {
String expected_value =
"Hello world"
;
Path path = Paths.get(
"src/test/resources/test_read.txt"
);
BufferedReader reader = Files.newBufferedReader(path);
String line = reader.readLine();
assertEquals(expected_value, line);
}
|
11. Conclusion
As you can see, there are many possibilities of reading data from a file using plain Java. You can go for BufferedReader to read line by line, Scanner to read using different delimiters, StreamTokenizer to read file into tokens, DataInputStream to read binary data and primitive data types, SequenceInput Stream to link multiple files into one stream,FileChannel to read faster from large files, etc.
写文件
Java – Write to File
1. Overview
In this tutorial we’ll explore different ways to write to a file using Java. We’ll make use ofBufferedWriter, PrintWriter, FileOutputStream, DataOutputStream, RandomAccessFile,FileChannel and the Java 7 Files utility class.
We’ll also take a look at locking the file while writing and discuss some final take-aways on writing to file.
This article is part of the “Java – Back to Basic” series here on Baeldung.
2. Write with BufferedWriter
Let’s start simple – and use BufferedWriter to write a String to a new file:
1
2
3
4
5
6
7
8
|
public
void
whenWriteStringUsingBufferedWritter_thenCorrect()
throws
IOException {
String str =
"Hello"
;
BufferedWriter writer =
new
BufferedWriter(
new
FileWriter(fileName));
writer.write(str);
writer.close();
}
|
The output in the file will be:
Hello
|
We can then append a String to the existing file:
1
2
3
4
5
6
7
8
9
10
|
@Test
public
void
whenAppendStringUsingBufferedWritter_thenOldContentShouldExistToo()
throws
IOException {
String str =
"World"
;
BufferedWriter writer =
new
BufferedWriter(
new
FileWriter(fileName,
true
));
writer.append(
' '
);
writer.append(str);
writer.close();
}
|
The file will then be:
1
|
Hello World
|
3. Write with PrintWriter
Next – let’s see how we can use a PrintWriter to write formatted text to a file:
1
2
3
4
5
6
7
8
9
|
@Test
public
void
givenWritingStringToFile_whenUsingPrintWriter_thenCorrect()
throws
IOException {
FileWriter fileWriter =
new
FileWriter(fileName);
PrintWriter printWriter =
new
PrintWriter(fileWriter);
printWriter.print(
"Some String"
);
printWriter.printf(
"Product name is %s and its price is %d $"
,
"iPhone"
,
1000
);
printWriter.close();
}
|
The resulting file will contain:
1
2
|
Some String
Product name is iPhone and its price is 1000$
|
Note how we’re not only writing a raw String to file, but also some formatted text with theprintf method.
We can create the writer using FileWriter, BufferedWriter or even System.out.
4. Write with FileOutputStream
Let’s now see how we can use FileOutputStream to write binary data to a file. The following code converts a String int bytes and writes the bytes to file using aFileOutputStream:
1
2
3
4
5
6
7
8
9
10
|
@Test
public
void
givenWritingStringToFile_whenUsingFileOutputStream_thenCorrect()
throws
IOException {
String str =
"Hello"
;
FileOutputStream outputStream =
new
FileOutputStream(fileName);
byte
[] strToBytes = str.getBytes();
outputStream.write(strToBytes);
outputStream.close();
}
|
The output in the file will of course be:
1
|
Hello
|
5. Write with DataOutputStream
Next – let’s take a look at how we can use a DataOutputStream to write a String to file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Test
public
void
givenWritingToFile_whenUsingDataOutputStream_thenCorrect()
throws
IOException {
String value =
"Hello"
;
FileOutputStream fos =
new
FileOutputStream(fileName);
DataOutputStream outStream =
new
DataOutputStream(
new
BufferedOutputStream(fos));
outStream.writeUTF(value);
outStream.close();
// verify the results
String result;
FileInputStream fis =
new
FileInputStream(fileName);
DataInputStream reader =
new
DataInputStream(fis);
result = reader.readUTF();
reader.close();
assertEquals(value, result);
}
|
6. Write with RandomAccessFile
Let’s now illustrate how to write and edit inside an existing file – rather than just writing to a completely new file or appending to an existing one. Simply put – we need random access.
RandomAccessFile enable us to write at a specific position in the file given the offset – from the beginning of the file – in bytes. The following code writes an integer value with offset given from the beginning of the file:
1
2
3
4
5
6
7
|
private
void
writeToPosition(String filename,
int
data,
long
position)
throws
IOException {
RandomAccessFile writer =
new
RandomAccessFile(filename,
"rw"
);
writer.seek(position);
writer.writeInt(data);
writer.close();
}
|
If we want to read the int stored at specific location, we can use the following method:
1
2
3
4
5
6
7
8
9
|
private
int
readFromPosition(String filename,
long
position)
throws
IOException {
int
result =
0
;
RandomAccessFile reader =
new
RandomAccessFile(filename,
"r"
);
reader.seek(position);
result = reader.readInt();
reader.close();
return
result;
}
|
To test our functions, let’s write an integer – edit it – and, finally, read it back:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
whenWritingToSpecificPositionInFile_thenCorrect()
throws
IOException {
int
data1 =
2014
;
int
data2 =
1500
;
writeToPosition(fileName, data1,
4
);
assertEquals(data1, readFromPosition(fileName,
4
));
writeToPosition(fileName2, data2,
4
);
assertEquals(data2, readFromPosition(fileName,
4
));
}
|
7. Write with FileChannel
If you are dealing with large files, FileChannel can be faster than standard IO. The following code write String to a file using FileChannel:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Test
public
void
givenWritingToFile_whenUsingFileChannel_thenCorrect()
throws
IOException {
RandomAccessFile stream =
new
RandomAccessFile(fileName,
"rw"
);
FileChannel channel = stream.getChannel();
String value =
"Hello"
;
byte
[] strBytes = value.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(strBytes.length);
buffer.put(strBytes);
buffer.flip();
channel.write(buffer);
stream.close();
channel.close();
// verify
RandomAccessFile reader =
new
RandomAccessFile(fileName,
"r"
);
assertEquals(value, reader.readLine());
reader.close();
}
|
8. Write to file using Java 7
Java 7 introduces a new way of working with the filesystem, along with a new utility class –Files. Using the Files class, we can create, move, copy, delete files and directories as well; it also can be used to read and write to a file:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Test
public
void
givenUsingJava7_whenWritingToFile_thenCorrect()
throws
IOException {
String str =
"Hello"
;
Path path = Paths.get(fileName);
byte
[] strToBytes = str.getBytes();
Files.write(path, strToBytes);
String read = Files.readAllLines(path).get(
0
);
assertEquals(str, read);
}
|
9. Write to temporary file
Now, let’s try to write to temporary file. The following code creates a temporary file and writes a String to it:
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test
public
void
whenWriteToTmpFile_thenCorrect()
throws
IOException {
String toWrite =
"Hello"
;
File tmpFile = File.createTempFile(
"test"
,
".tmp"
);
FileWriter writer =
new
FileWriter(tmpFile);
writer.write(toWrite);
writer.close();
BufferedReader reader =
new
BufferedReader(
new
FileReader(tmpFile));
assertEquals(toWrite, reader.readLine());
reader.close();
}
|
So, as you can see – it’s just the creation of the temporary file that is interesting and different – after that point, writing to the file is the same.
10. Lock File Before Writing
Finally, when writing to a file, you sometimes need to make extra sure that no one else is writing to that file at the same time. Basically – you need to be able to lock that file while writing.
Let’s make use of the FileChannel to try locking the file before writing to it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Test
public
void
whenTryToLockFile_thenItShouldBeLocked()
throws
IOException {
RandomAccessFile stream =
new
RandomAccessFile(fileName,
"rw"
);
FileChannel channel = stream.getChannel();
FileLock lock =
null
;
try
{
lock = channel.tryLock();
}
catch
(
final
OverlappingFileLockException e) {
stream.close();
channel.close();
}
stream.writeChars(
"test lock"
);
lock.release();
stream.close();
channel.close();
}
|
Note that if the file is already locked when we try to acquire the lock, anOverlappingFileLockException will be thrown.
11. Notes
After exploring so many methods of writing to a file, let’s discuss some important notes:
- If we try to read from a file that doesn’t exist, a FileNotFoundException will be thrown
- If we try to write to a file that doesn’t exist, the file will be created first and no exception will be thrown
- It is very important to close the stream after using it, as it is not closed implicitly, to release any resources associated with it
- In output stream, the close() method calls flush() before releasing the resources which forces any buffered bytes to be written to the stream
Looking at the common usage practices, we can see – for example – that PrintWriter is used to write formatted text; FileOutputStream to write binary data; DataOutputStream to write primitive data types; RandomAccessFile to write to a specific position; FileChannel to write faster in larger files. Some of the APIs of these classes do allow more, but this is a good place to start.
12. Conclusion
This article illustrates the many options of writing data to a File using Java.
The implementation of all these examples and code snippets can be found in my github project – this is an Eclipse based project, so it should be easy to import and run as it is.