1.概述
在本教程中,我们将探索使用Java写入文件的不同方法。我们将使用BufferedWriter,PrintWriter,FileOutputStream,DataOutputStream,RandomAccessFile,FileChannel和Java 7 Files实用程序类。
2.使用BufferedWriter编写
让我们开始简单 - 并使用BufferedWriter将String 写入新文件:
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(); } |
文件中的输出将是:
然后我们可以将String附加到现有文件:
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(); } |
该文件将是:
3.使用PrintWriter写入
接下来 - 让我们看看如何使用PrintWriter将格式化文本写入文件:
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(); } |
生成的文件将包含:
1 2 | Some String Product name is iPhone and its price is 1000$ |
请注意我们不仅要将原始String写入文件,还要使用printf方法编写一些带格式的文本。
我们可以使用FileWriter,BufferedWriter甚至System.out创建编写器。
4.使用FileOutputStream写入
现在,让我们看看我们如何能够利用FileOutputStream中,以二进制数据写入一个文件。以下代码转换String int bytes并使用FileOutputStream将字节写入文件:
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(); } |
文件中的输出当然是:
5.使用DataOutputStream编写
接下来 - 让我们看一下如何使用DataOutputStream将String写入文件:
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.使用RandomAccessFile写入
现在让我们说明如何在现有文件中编写和编辑 - 而不是仅仅写入一个全新的文件或附加到现有文件。简单地说 - 我们需要随机访问。
RandomAccessFile使我们能够在给定偏移量的文件中的特定位置写入 - 从文件的开头 - 以字节为单位。以下代码写入一个整数值,其中包含从文件开头给出的偏移量:
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(); } |
如果我们想要读取存储在特定位置的int,我们可以使用以下方法:
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; } |
为了测试我们的函数,让我们写一个整数 - 编辑它 - 最后,读回来:
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.使用FileChannel写入
如果您正在处理大文件,FileChannel可能比标准IO更快。以下代码使用FileChannel将String写入文件:
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.使用Java 7写入文件
Java 7引入了一种使用文件系统的新方法,以及一个新的实用程序类 - Files。使用Files类,我们也可以创建,移动,复制,删除文件和目录; 它还可用于读取和写入文件:
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.写入临时文件
现在,让我们尝试写入临时文件。以下代码创建一个临时文件并将String写入其中:
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(); } |
因此,正如您所看到的 - 它只是创建了有趣且不同的临时文件 - 在此之后,写入文件是相同的。
10.写入前锁定文件
最后,在写入文件时,有时需要确保没有其他人同时写入该文件。基本上 - 您需要能够在写入时锁定该文件。
让我们使用FileChannel在写入之前尝试锁定文件:
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(); } |
请注意,如果在我们尝试获取锁时文件已被锁定,则将抛出OverlappingFileLockException。
11.备注
在探索了很多写入文件的方法之后,让我们讨论一些重要的注意事项:
- 如果我们尝试从不存在的文件中读取,则会抛出FileNotFoundException
- 如果我们尝试写入不存在的文件,将首先创建该文件,不会抛出任何异常
- 在使用它之后关闭流是非常重要的,因为它没有隐式关闭,以释放与之关联的任何资源
- 在输出流中,close()方法在释放资源之前调用flush(),这会强制将任何缓冲的字节写入流中
查看常见的使用方法,我们可以看到 - 例如 - PrintWriter用于编写格式化文本; FileOutputStream写入二进制数据; DataOutputStream用于写入原始数据类型; RandomAccessFile写入特定位置; FileChannel可以在更大的文件中更快地写入。这些类的一些API确实允许更多,但这是一个很好的起点。
12.结论
本文说明了使用Java将数据写入文件的许多选项。
所有这些示例和代码片段的实现都可以在GitHub项目中找到 - 这是一个基于Maven的项目,因此它应该很容易导入和运行。