FileChannel 和 ByteBuffer 的使用

目录

 

1、存入文件

2、读取文件

3. 直接将数据从一个文件通道写入另一个文件通道

4. 直接内存


1、存入文件

下面给个例子,简单地把内容写入到指定文件中。

public class FileChannelTest {
    public static void main(String[] args){
        try {
            // 先把字符串内容写入source.txt文件中
            String message = "hello, how are you?";
            // 创建一个bytebuffer内存块
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 将字符串内容存入bytebuffer
            byteBuffer.put(message.getBytes());
            // 创建文件输出流
            FileOutputStream fileOutputStream = new FileOutputStream("./src/fileChannel/source.txt");
            // 创建文件通道
            FileChannel fileChannel0 = fileOutputStream.getChannel();
            // 切换到读模式
            byteBuffer.flip();
            // 将bytebuffer中的内容写入到通道中
            fileChannel0.write(byteBuffer);
            // 关闭资源
            fileChannel0.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下,字符串已经成功写入到文件中。 

        

2、读取文件

下面给了一个简单的例子,从文件中读取数据。

public class FileChannelTest1 {
    public static void main(String[] args){
        try {
            // 创建文件输入流
            FileInputStream fileInputStream = new FileInputStream("./src/fileChannel/source.txt");
            // 创建一个bytebuffer内存块
            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
            // 创建文件通道
            FileChannel fileChannel = fileInputStream.getChannel();
            // 从文件通道中读取内容到bytebuffer中
            fileChannel.read(byteBuffer);
            // 输出读取到的内容
            System.out.println(new String(byteBuffer.array()));
            // 关闭资源
            fileChannel.close();
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下。

       

3. 直接将数据从一个文件通道写入另一个文件通道

下面是一个简单的例子,关键在于两个方法,这两个方法是使用了零拷贝。

transferFrom(ReadableByteChannel src, long position, long count)

transferTo(ReadableByteChannel src, long position, long count)

其实这个两个方法效果一样的,只不过是源通道和目的通道的视角不同而已。

public class FileChannelTransferTest {
    public static void main(String[] args){
        try {
            // 创建文件输入流
            FileInputStream fileInputStream = new FileInputStream("./src/fileChannel/source.txt");
            // 创建文件通道
            FileChannel fileChannelSource = fileInputStream.getChannel();
            // 创建文件输出流
            FileOutputStream fileOutputStream = new FileOutputStream("./src/fileChannel/destination.txt");
            // 创建文件通道
            FileChannel fileChannelDestination = fileOutputStream.getChannel();
            // 将文件数据从源通道传入目的通道,达到将文件数据复制到另一个文件中去
            fileChannelSource.transferTo(0, fileInputStream.available(), fileChannelDestination);
            // 关闭资源
            fileChannelSource.close();
            fileChannelDestination.close();
            fileInputStream.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下,destination.txt 文件中已经有了 source.txt 文件中的内容了。

         

4. 直接内存

我们之前用的ByteBuffer,其实底层是 HeapByteBuffer,这种内存块是属于应用层的JVM所管理的,是用户态的,于是就会出现数据在内核态和用户态之间的复制,但是可以省去这个复制工作,用的技术就是零拷贝技术,即直接内存。

MappedByteBuffer 就是直接内存,它将文件中的内容映射到直接内存中,我们读取文件也好,往文件中写入数据也好,就是直接针对于直接内存的,然后系统底层会自动为我们将数据的改变持久化到磁盘文件中的。

下面给一个简单的例子。

public class DirectByteBufferTest {
    public static void main(String[] args) throws IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile("./src/fileChannel/source.txt", "rw");
        FileChannel fileChannel = randomAccessFile.getChannel();
        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, randomAccessFile.length());
        mappedByteBuffer.put("I am fine, thanks".getBytes());
        fileChannel.close();
        randomAccessFile.close();
    }
}

运行结果如下。

        

出现这种结果的原因是,我们将 source.txt 文件的全部内容都映射到了直接内存,也写入了“I am fine, thanks”,它是从文件开始出以覆盖的方式写入,因此覆盖了之前的内容,只剩下了“u?”。

再看看 MappedByteBuffer 的全部读写操作,其实是继承自 ByteBuffer 的,使得控制起来更加灵活。

ByteBuffer put(byte b);  // 以覆盖的方式写入文件一个字节。

ByteBuffer put(byte[] array);  //以覆盖的方式写入一个字节数组。

ByteBuffer put(ByteBuffer buffer);  // 以覆盖的方式写入一个 ByteBuffer 的内容。

ByteBuffer put(int index,  byte b);  // 以覆盖的方式在位置 index 处写入一个字节。

ByteBuffer put(byte[] array, int offset, int length); // 以覆盖的方式写入一个字节数组的 offset 到 offset + length - 1 范围的字节。

ByteBuffer putChar(char value); //以覆盖的方式写入一个字符。

ByteBuffer putChar(char value, int index); // 以覆盖的方式在index处写入一个字符。

当然类似的还有:putInt(), putFloat(), putDouble(),putLong(),putShort()。

byte get(); // 获取文件的一个字节

byte get(int index);  //获取文件index处的一个字节

Bytebuffer  get(byte[] dst); // 获取文件的内容,尽量填满 dst 数组。

ByteBuffer get(byte[] dst, int offset, int length); // 获取文件的内容,尽量填满 dst 数组的 offset 到 offset + length - 1 范围。

char getChar(); // 获取文件一个字符

char getChar(int index); // 获取文件的 index 位置处的一个字符

类似的还有:getInt(), getLong(), getShort(), getFloat(), getDouble()。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值