Java NIO -- FileChannel

本文详细介绍了 Java NIO 中 FileChannel 类的基本使用,包括如何创建、读取和写入文件,以及 Buffer 和 Channel 的核心概念。示例代码展示了如何在 Windows OS 和 JavaSE7 上使用 FileChannel 进行文件操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源文出处:http://examples.javacodegeeks.com/core-java/nio/filechannel/java-nio-channels-filechannel-example/

本文主要介绍FileChannel类和它的简单使用(使用FileChannel读写文件)。该类作为Java NIO(New IO)File API的一部分,从Java1.4开始支持。
注意:本文中的范例代码编译并运行在Windows OS 和 Java SE 7上。

1. 介绍

NIO使得Java程序员不需要写过多的Code就可以实现高性能的I/O。NIO把最消耗性能的操作(例如:filling 和 draining buffers)交给了操作系统,因此在JavaSE5, 6, 7版本上 NIO(和IO)的性能有了提高。
Buffer和Channel是NIO的主要概念。

2. Buffers and Channels

Buffer提供了一套可以存储固定数量原始数据元素的内存容器。在NIO中,所有的数据都是用Buffer处理。读数据时,把数据直接读入Buffer。写数据时,同样也把数据写入Buffer。Buffer搭配Channel一起使用。Channel是I/O传输发生的入口,Buffer是数据传输的源头或是目的地。

3. 使用FileChannel读写文件

 Filechannel是阻塞的读写管道. 它可以用于读,写,mapping和manipulating 一个文件. FileChannel 对象是线程安全的。一个FileChannel 实例可以通过RandomAccessFile, FileInputStream或 FileOutputStream类中的getChannel()方法得到,或是通过FileChannel的静态open()方法获取。本文会介绍这两种获取FileChannel 对象的方法。

4. 读文件

 这个例子介绍了使用FileChannel读一个文件进入Buffer并打印Buffer内容。

4.1. 输入文件

一个文本文件,内容:1234567890

4.2.创建FileChannel对象

FileChannel类中的静态方法open()用于创建一个管道。该方法打开一个文件,返回一个可以访问指定文件的FileChannel对象。

    Path path = Paths.get("readfile.txt");
    FileChannel fileChannel = FileChannel.open(path);

4.3. 创建一个Buffer

使用ByteBuffer的allocate()静态方法创建一个ByteBuffer 对象。这个像Buffer的位置是0,它的limit是它的容量,它的元素将被初始化为0。在本例中,初始化的容量为6.

   ByteBuffer buffer = ByteBuffer.allocate(6);

4.4. 从管道中读入Buffer

FileChannel的read()方法读一组字节进入所给的Buffer。该方法返回所读字节的数量,如果管道已经到了流的末尾返回-1.

    int noOfBytesRead = fileChannel.read(buffer);

从管道的当前位置(初始值为0)读取字节,根据实际读取的字节数更新文件的位置(例如:在读完一次后位置为6)。管道的position()方法返回当前的位置。ByteBuffer 也有一个position()方法。初始值为0。读完一次后,该值为6。ByteBuffer 的flip()方法是的ByteBuffer 可以为get操作准备好数据序列:它设置limit为当前的position(在本例中为6)然后设置position为0.

    buffer.flip();

4.5. 打印Buffer中的数据

    while (buffer.hasRemaining()) {
       System.out.print((char) buffer.get());
    }

ByteBuffer 的clear()方法可以为channel-read操作准备好数据序列,它设置limit为capacity(6)并设置position为0.

    buffer.clear();

4.6. 关闭管道

FileChannel的close()方法可以关闭管道。
异常:
在这个例子中, FileChannel的open(), close(), position() 和read() 方法抛 IOException

下面是完整的代码:

import java.io.file.Paths;
import java.nio.file.Path;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.FileReader;
import java.io.BufferedReader;

public class FileChannelRead {
    public static void main (String [] args)
            throws Exception {

        new FileChannelRead().readFile();
    }
    private void readFile()
            throws IOException {

        String filePath = "readfile.txt";
        printFileContents(filePath);
        Path path = Paths.get(filePath);

        FileChannel fileChannel =  FileChannel.open(path);
        ByteBuffer buffer = ByteBuffer.allocate(6);
        int noOfBytesRead = fileChannel.read(buffer);

        while (noOfBytesRead != -1) {
            System.out.println("Number of bytes read: " + noOfBytesRead);
            buffer.flip();
            System.out.print("Buffer contents: ");

            while (buffer.hasRemaining()) {
                System.out.print((char) buffer.get());                    
            }

            System.out.println(" ");
            buffer.clear();
            noOfBytesRead = fileChannel.read(buffer);
        }
        fileChannel.close();
    }
    private void printFileContents(String path)
            throws IOException {

        FileReader fr = new FileReader(path);
        BufferedReader br = new BufferedReader(fr);
        String textRead = br.readLine();
        System.out.println("File contents: ");

        while (textRead != null) {
            System.out.println("     " + textRead);
            textRead = br.readLine();
         }
         fr.close();
         br.close();
    }
}

输出是:

File contents: 1234567890
Number of bytes read: 6
Buffer contents: 123456
Number of bytes read: 4
Buffer contents: 7890

输出:
文件内容: 1234567890;
读取的字数数量: 6, 缓冲内容: 123456. 这个第一次读。前6个字节从管道读入缓冲,缓冲中的内容是 123456。
注意: 这个点缓冲和管道的位置是6。缓冲的flip()的方法把位置改为0。然后读取的字节数量为4,缓冲内容为7890。这是第二次的读取,也是最后一次。有四个字数被读取并打印。
注意: 现在管道的位置为 10,缓冲的位置为 4

5. 写文件

这个例子给出了通过管道从缓存中读数据并写文件的步骤,最后打印文件的内容。

5.1. 输入

输入是一个字符串。这个字符串被转换成字节数组,然后赋给buffer。

    String input = "file channel example";
    byte [] inputBytes = input.getBytes();

5.2. 创建buffer:

FileChannel的wrap()静态方法可以把自己数组放入一个buffer。这个新的buffer的capacity和limit是数组的长度,它的初始position是0.

   ByteBuffer buffer = ByteBuffer.wrap(inputBytes);

5.3. 创建管道:

FileOutputStream的getChannel()方法可以创建管道。这个方法返回一个连着这个文件的管道。

   String filePath = "writefile.txt";
   FileOutputStream fos = new FileOutputStream(filePath);
   FileChannel fileChannel = fos.getChannel();

注意:这个例子中,开始文件并不存在。上面的代码块会创建它。

5.4. 把Buffer中的数据写入管道连接的文件

FileChannel的write() 方法可以把buffer中的字节数组写入这个管道。从管道中当前文件的位置开始写入字节(这里position为0)。

   int noOfBytesWritten = fileChannel.write(buffer);

5.5. 关闭管道:

关闭文件管道和文件输出流:

    fileChannel.close();
    fos.close();

5.6. 打印文件内容:

打印文件内容到终端输出。

异常:
FileOutputStream的构造方法抛 FileNotFoundException.
FileChannel的 write(), close()方法和FileOutputStream的 close() 方法抛IOException.
下面是使用管道写文件的完整代码块:

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.io.FileReader;
import java.io.BufferedReader;

public class FileChannelWrite {
    public static void main (String [] args)
            throws Exception {

        new FileChannelWrite().writeFile();
    }
    private void writeFile()
            throws IOException {

        String input = "file channel example";
        System.out.print("Input string: " + input);

        byte [] inputBytes = input.getBytes();
        ByteBuffer buffer = ByteBuffer.wrap(inputBytes);

        String filePath = "writefile.txt";
        FileOutputStream fos = new FileOutputStream(filePath);
        FileChannel fileChannel = fos.getChannel();
        fileChannel.write(buffer);
        fileChannel.close();
        fos.close();

        printFileContents(filePath);
    }
    private void printFileContents(String path)
            throws IOException {

        FileReader fr = new FileReader(path);
        BufferedReader br = new BufferedReader(fr);
        String textRead = br.readLine();
        System.out.println("File contents: ");

        while (textRead != null) {

            System.out.println("     " + textRead);
            textRead = br.readLine();
        }
        fr.close();
        br.close();
    }
}

6. lock()和tryLock()方法

下面是lock()和tryLock()方法的使用总结:

Case1. 一个Java程序锁了这个文件,其它的程序(如写字板)不能修改或保存这个被锁的文件。

Case 2: 当一个软件 (e.g. Excel) 锁一个文件,如果你调用tryLock()方法, 将会抛FileNotFoundException

Case 3: 如果在同一个线程或是不同的线程中多次调用tryLock()方法,将抛 OverlappingFileLockException

Case 4: 当一个JVM调用lock()方法锁住一个文件,如果另一个JVM调用tryLock()/lock()方法锁一个文件,tryLock()方法会立即返回null,lock()方法会一直阻塞直到之前的JVM释放锁。

参考http://blog.youkuaiyun.com/totogogo/article/details/3123117

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值