Java IO常用操作(一)写文件

在Java中对系统文件进行写入是一种很常见的操作,本文总结了写文件的一些常用实现,并对其进行对比。

BufferedWriter

首先使用BufferedWriter向新文件中写入简单的字符串:

@Test
public void writeStringsWithBufferedWriter() throws IOException{
    String str = "test";
    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
    writer.write(str);
    
    writer.close()
}
复制代码

执行程序后,文件中的内容为:

test
复制代码

我们同样可以在已有的文件中追加字符串:

@Test
public void appendStringsWithBufferedWriter() throws IOException{
    String str = " Hello,World";
    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName true));
    writer.append(str);
    
    writer.close();
}
复制代码

执行之后,文件内容变为:

test Hello,World
复制代码

PrintWriter

使用PrintWriter可以向文件中写入格式化的文本

@Test
public void writeStringWithPrintWriter() throws IOException{
    FileWriter writer = new FileWriter(fileName);
    PrintWriter printWriter = new PrintWriter(fileWriter);
    printWriter.print("test1");
    printWriter.printf("string %s, num %d", "formatString", 10);
    printWriter.close();
}
复制代码

文件内容为

test1
string formatString,num 10
复制代码

我们可以利用FileWriterBufferedWriter甚至是System.out来构造PrintWriter,通过PrintWriter不仅可以向文件中写入原生字符串,而且可以利用printf方法写入格式化的文本。

FileOutputStream

使用FileOutputStream可以向文本中写入二进制数据,示例如下:

@Test
public void writeFileWithFileOutputStream() throws IOException{
    String str = "test";
    FileOutputStream stream = new FileOutputStream(fileName);
    byte[] bytes = str.getBytes();
    stream.write(bytes);
    stream.close();
}
复制代码

DataOutputStream

@Test
public void writeFileWithDataOutputStream() throws IOExeption{
    String str = "test";
    FileOutputStream fos = new FileOutputStream(fileName);
    DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(fos));
    dos.write(str);
    dos.close();
}
复制代码

RandomAccessFile

目前为止,我们都只是写全新的文件或者是在已有文件中追加新的内容,但是很多时候我们需要在已有文件中写入内容或者编辑内容,也就是要对文件进行随机访问RandomAccessFile在给定偏移值后,就可以向文件中的特定位置写入二进制内容,下例中的代码可以在文件的特定位置写入一个数字:

void writeIntOnPosition(String fileName, int data, long position) throws IOException{
    RandomAccessFile writer = new RandomAccessFile(fileName, "rw");
    writer.seek(position);
    writer.writeInt(data);
    writer.close();
}
复制代码

可以使用类似的方式实现从特定位置读取数字:

int readIntOnPosition(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;
}
复制代码

可以通过下面的方法进行简单的测试:

@Test
public void writeFileWithRandomAccessFile() throws IOException{
    int origin_int = 1;
    int change_int = 2;
    long position = 12;
    
    writeIntOnPosition(fileName, origin_int, position);
    assertEquals(origin_int, readIntOnPosition(fileName, position));
    
    writeIntOnPosition(fileName, change_int, position);
    assertEquals(change_int, readIntOnPosition(fileName, position));
}
复制代码

FileChannel

对于大文件的操作,FileChannel比标准IO接口更高效。使用示例如下:

@Test
public void writeFileWithFileChannel() throws IOException{
    RandomAccessFile stream = new RandomAccessFile(fileName, "rw");
    FileChannel channel = stream.getChannel();
    String str = "test";
    byte[] bytes = str.getBytes();
    ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
    buffer.put(bytes);
    buffer.flip();
    channel.write(buffer);
    stream.close();
    channel.close();
    
    RandomAccessFile reader = new RandomAccessFile(fileName, "r");
    assertEquals(str, reader.readLine());
    reader.close()
}
复制代码

使用Java 7

在Java 7中,引入了新的工具类Files,提供了一种操作文件系统的新方式。通过该工具类,可以对文件和目录进行新增、复制、删除、移动等操作,同样也可以用来读写文件内容:

@Test
public void writeFileWithJava7() throws IOException{
    String str = "test";
    Path path = Paths.get(fileName);
    byte[] bytes = str.getBytes();
    Files.write(path, bytes);
    String read = Files.readAllLines(path).get(0);
    asserEquals(str, read);
}
复制代码

写入临时文件

接下来,我们尝试对临时文件进行写操作:

@Test
public void writeToTmpFile() throws IOException {
    String str = "Hello";
    File tmpFile = File.createTempFile("test", ".tmp");
    FileWriter writer = new FileWriter(tmpFile);
    writer.write(str);
    writer.close();
 
    BufferedReader reader = new BufferedReader(new FileReader(tmpFile));
    assertEquals(str, reader.readLine());
    reader.close();
}
复制代码

可以看出,除了临时文件的创建之外,其余操作都是大同小异的。

写操作之前对文件加锁

有时候,我们在对文件进行写操作之前,需要保证其他人不会同时对该文件进行修改,也就是说我们需要在写文件时对其进行加锁

在对文件写入之前,我们可以使用FileChannel尝试对文件进行加锁:

@Test
public void tryLockFileBeforeWrite() 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.release();
    stream.close();
    channel.close();
}
复制代码

注意,如果我们尝试获取锁时,文件处于已加锁状态,则会抛出OverlappingFileLockException

总结

以上的方法都能实现写文件的目的,但是仍有一些需要注意的地方:

  • 如果尝试读一个不存在的文件,会抛出FileNotFoundException
  • 如果尝试写一个不存在的文件,会先创建该文件,不会抛出异常。
  • 在使用完流对象之后,一定要及时关闭以释放相关系统资源,这一点非常重要,因为流对象不会隐式自动关闭。
  • 在输出流中,close()方法在释放系统资源之前会首先调用flush()方法,强制将缓存的数据写入流中。

通常来说,PrintWriter用于编写格式化文本,FileOutputStream用于写二进制数据,DataOutputStream用于写基本数据类型,RandomAccessFile用于在特定位置对文件进行操作,FileChannel对于大型文件的操作更加高效。虽然这些API都可以提供很多功能,但是根据不同的使用场景选择合适的方案会更加便利。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值