FileChannel主要方法的使用

FileChannel介绍

FileChannel类是Channel接口的主要实现类,Channel是NIO的重要组件之一。
FileChannel类的主要作用是读取、写入、映射、操作文件。

write

public abstract int write(ByteBuffer src) throws IOException;

FileChannel内部维护了一个当前文件的position,可以查询、修改position。

/**
 * int write(ByteBuffer src)将src的remaining的字节写入FileChannel的position。
 * @throws Exception
 */
@Test
public void testWrite() throws Exception {
    FileOutputStream fos = new FileOutputStream("d:/1.txt");
    FileChannel fileChannel = fos.getChannel();
    ByteBuffer b = ByteBuffer.wrap(new byte[]{1,2,3,4,5});
    int result = fileChannel.write(b);
    System.out.println("写入了" + result+ "个字节");  // 1,2,3,4,5
    System.out.println("fileChannel.position()=" + fileChannel.position());


    fileChannel.position(2);//设置FileChannel的position位置是2
    b.rewind();
    result = fileChannel.write(b); //1,2,1,2,3,4,5
    System.out.println("写入了" + result+ "个字节");

    b.position(4);
    result = fileChannel.write(b);
    System.out.println("写入了" + result+ "个字节"); //1,2,1,2,3,4,5,5
    fos.close();
}
/**
 * int write(ByteBuffer src)是同步的,同一时间只能有一个线程写入
 * @throws Exception
 */
@Test
public void testWrite2() throws Exception {
    FileOutputStream fos = new FileOutputStream("d:/1.txt");
    FileChannel fileChannel = fos.getChannel();
    ExecutorService exec = Executors.newFixedThreadPool(100);
    for (int i = 0; i < 200; i++) {
        exec.execute(()->{
            int i2 = new Random().nextInt(2);
            ByteBuffer byteBuffer;
            if(i2 % 2 == 0){
                byteBuffer = ByteBuffer.wrap((Thread.currentThread().getName() + "写入abcde\n").getBytes());
            }else{
                byteBuffer = ByteBuffer.wrap((Thread.currentThread().getName() + "写入12345\n").getBytes());
            }
            try {
                Thread.sleep(1);
                fileChannel.write(byteBuffer);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
    exec.shutdown();
    while(!exec.isTerminated()){
        Thread.sleep(1000);
    }
}

在这里插入图片描述
写入的文件没有发生数字和字母混合在同一行的情况。

其他write方法

write(ByteBuffer[] srcs) 将ByteBuffer数组srcs里的内容(都是从position到limit处的内容)批量写到当前FileChannel的position开始处。
write(ByteBuffer src, long position)向FileChannel通道的指定position写入src的remaining内容。

read()

和write()一样,同一时间只能有1个线程读取,其他线程阻塞。

public abstract int read(ByteBuffer dst) throws IOException

read方法返回读取了多少个字节,如果是末尾,返回-1。如果dst的remaining用完了,返回0.
read方法会将FileChannel当前position读入1个到dst的remaining字节空间。

/**
 * 假设1.txt里写入了5个字节:
 * ByteBuffer b = ByteBuffer.wrap(new byte[]{1,2,3,4,5});
 * fileChannel.write(b);
 * @throws Exception
 */
@Test
public void testRead() throws Exception {
    FileInputStream fis = new FileInputStream("d:/1.txt");
    FileChannel fileChannel = fis.getChannel();
    ByteBuffer byteBuffer = ByteBuffer.allocate(5);
    int resultBytesCount = fileChannel.read(byteBuffer);
    System.out.println("读取了" + resultBytesCount+"个字节");   //读取了5个字节
    System.out.println("fileChannel.position()=" + fileChannel.position()); //fileChannel.position()=5

    resultBytesCount = fileChannel.read(byteBuffer);
    System.out.println("读取了" + resultBytesCount+"个字节");  //读取了0个字节
    System.out.println("fileChannel.position()=" + fileChannel.position()); //fileChannel.position()=5

    byteBuffer.clear();
    resultBytesCount = fileChannel.read(byteBuffer);
    System.out.println("读取了" + resultBytesCount+"个字节");  //读取了-1个字节,因为FileChannel已经到头了
    System.out.println("fileChannel.position()=" + fileChannel.position()); //fileChannel.position()=5

    fileChannel.position(1);
    byteBuffer.position(1);
    resultBytesCount = fileChannel.read(byteBuffer); //从byteBuffer的position=1处开始读,读入到fileChannel的position=1处
    System.out.println("读取了" + resultBytesCount+"个字节");  //读取了4个字节
    System.out.println("fileChannel.position()=" + fileChannel.position()); //fileChannel.position()=5

    fileChannel.close();;
    fis.close();
}

在这里插入图片描述

其他read方法

read(ByteBuffer[] dsts) 将FileChannel的当前position开始字节读取到,ByteBuffer数组dsts的每一个ByteBuffer的position到limit。
int read(ByteBuffer dst, long position) 将FileChannle的指定position开始的内容读入到dst的position处。

size

long size() 返回此FileChannel关联文件的大小

例如使用FileChannel完成文件的读取

/**
 * 假定文件已经存在,使用ByteBuffer和FileChannel将文件中的数据读入到程序,并显示在控制台屏幕。
 */
@Test
public void testSize() throws Exception {
    File file = new File("d:\\1.txt");
    FileInputStream fileInputStream = new FileInputStream(file);
    FileChannel fileChannel = fileInputStream.getChannel();
    ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size());
    fileChannel.read(byteBuffer);
    //将byteBuffer 的 字节数据 转成String
    System.out.println(new String(byteBuffer.array()));
    fileInputStream.close();
}

/**
 * 使用 FileChannel完成文件的拷贝。拷贝一个文件 1.txt
 */
public void testReadAndWrite() throws Exception{
    FileInputStream fileInputStream = new FileInputStream("1.txt");
    FileChannel fileChannel1 = fileInputStream.getChannel();

    FileOutputStream fileOutputStream = new FileOutputStream("2.txt");
    FileChannel fileChannel2 = fileOutputStream.getChannel();

    ByteBuffer byteBuffer = ByteBuffer.allocate(512);
    while (true) {
        byteBuffer.clear(); //清空buffer
        int read = fileChannel1.read(byteBuffer);
        if(read == -1) { //表示读完
            break;
        }
        byteBuffer.flip();
        fileChannel2.write(byteBuffer);
    }
    fileInputStream.close();
    fileOutputStream.close();
}

transFrom & transTo

long transferFrom(ReadableByteChannel src,long position, long count) 将数据从src通道中的position开始传输最大count个字节到当前FileChannel通道。
long transferTo(long position, long count,WritableByteChannel target) 将FileChannel中position处开始的字节传输最大count个字节到另外一个通道。如果position>FileChannel大小,不传输任何字节。

用transFrom完成文件的拷贝

/**
 * 使用 FileChannel(通道) 和 方法  transferFrom ,完成文件的拷贝
 */
public void testTransferFrom() throws Exception{
    FileInputStream fileInputStream = new FileInputStream("d:\\1.txt");
    FileOutputStream fileOutputStream = new FileOutputStream("d:\\1.txt");
    FileChannel sourceCh = fileInputStream.getChannel();
    FileChannel destCh = fileOutputStream.getChannel();
    //使用transferForm完成拷贝
    destCh.transferFrom(sourceCh,0,sourceCh.size());
    //关闭相关通道和流
    sourceCh.close();
    destCh.close();
    fileInputStream.close();
    fileOutputStream.close();
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值