天天看点

java文件读写之Channel策略

概述

本篇博客向大家介绍的是如何运用java中的Channel进行文件读写,也就是说明如何通过Channel将字符串写到文件中,以及怎么把文件中的内容以字符串的形式读出来。具体地,我会介绍关于Channel和缓冲区的一些内容。

什么是通道

那么肯定就有一些同学不太知道什么是通道(Channel),所以在开始介绍之前,我们首先要对通道有一个说明。由 java.nio.channels 包定义的,也就是说Channel是java New I/O中的一种,Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel本身不能直接访问数据, Channel 只能与Buffer 进行交互。

如何获取通道

获取通道的方式有很多,这里只介绍其中一种,就是对支持通道的对象调用getChannel() 方法。支持通道的类如下:

  • FileInputStream
  • FileOutputStream
  • RandomAccessFile
  • DatagramSocket
  • Socket
  • ServerSocket

Channel策略主要思想

从文件中读:我们知道文件是可以以流的方式打开的,然后用流的getChannel() 方法即可以获取通道。然后用一个固定大小的缓存区多次从通道中读出内容即可。

往文件里写:同样的以流的方式打开文件,然后用流的getChannel() 方法即可以获取通道,之后再将要写入的字符串放入缓存区中,缓存区的内容通过通道就可以写到文件中去了。

缓冲区的一些内容

以下内容来自缓冲区(Buffer)这篇博客将缓冲区介绍的清晰明了,我截取其中一些内容放到这里方便大家看。

1、缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对I/O的数据做临时存储,这部分预留的内存空间叫缓冲区。使用缓冲区有两个好处:减少实际物理读写次数;缓冲区在创建时就被分配内存,这块内存区域一直被重用,可以减少动态分配和回收内存的次数。

2、所有缓冲区都有4个属性:capacity、limit、position、mark,并遵循mark<=position<=limit<=capacity,下表时对这4个属性的解释:

字段 作用
position 当前读到的位置
limit 当前写到的位置
capacity 容量
mark 标记,调用mark()来设置mark=position,在调用reset()可以让position恢复到标记位置

3、一些重要方法

方法 描述
flip() limit=position,position=0,mark=-1;将缓冲区状态由存数据变为准备取数据
limit(),limit(10) 前者get,后者set
hasRemaining() return position < limit,是否还有未读内容

Channel策略实现方法

从文件中读:首先我们通过FileInputStream f1 = new FileInputStream(filename);一句获取文件的读入流。然后利用FileChannel fc1 = f1.getChannel();获取读入流的通道。之后就是声明一个缓冲区,因为是字节流,所以我们声明一个bytebuffer,如:ByteBuffer b1 = ByteBuffer.allocate(1024);1024代表缓冲区的大小为1024字节,可以根据自己需要更改的。然后,调用FileChannel.read()方法。该方法将数据从FileChannel读取到Buffer中。read()方法返回的int值表示了有多少字节被读到了Buffer中。如果返回-1,表示到了文件末尾。至此我们已将一部分内容读入到了bytebuffer中,不过我们的最终目的是将内容读入到字符串中,所有要进行一个转换。另外,缓冲区太小导致不能一次读完内容的时候还要清空缓存区多次读取。

往文件里写:同样先通过FileOutputStream f1 = new FileOutputStream(filename);获取文件的输出流,然后输出流的getChannel() 方法即可以获取通道,之后通过ByteBuffer buffer = ByteBuffer.wrap(outString.getBytes());将要写入的字符串放入缓存区中,最后调用fc1.write(buffer);就完成写文件了。

代码展示

package readandwrite;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Channel {
  
  public String myread(String filename) throws Exception {
    // TODO 自动生成的方法存根
    long starttime = System.currentTimeMillis();
    StringBuilder result = new StringBuilder();
    try {
      FileInputStream f1 = new FileInputStream(filename); 
      FileChannel fc1 = f1.getChannel();
      ByteBuffer b1 = ByteBuffer.allocate(1024);//初始化缓冲区大小
      while (fc1.read(b1) != -1) {
        int temp = b1.limit();
        b1.flip();
        while (temp != 0 && b1.hasRemaining()) {//这里temp不为0是为了确保缓存区的有效内容不为空
          result.append((char)b1.get());
        }
        b1.clear();
      }
      fc1.close();
      f1.close();
    } catch (Exception e) {
      // TODO: handle exception
      throw new Exception(e.toString());
    }
    long endtime = System.currentTimeMillis();
    System.out.println("Channel策略读文件花费了:" + (endtime - starttime) + "ms");
    return result.toString();
  }
  
  public void mywrite(String outString, String filename) throws Exception {
    // TODO 自动生成的方法存根
    long starttime = System.currentTimeMillis();
    try {
      FileOutputStream f1 = new FileOutputStream(filename);
      FileChannel fc1 = f1.getChannel();
      ByteBuffer buffer = ByteBuffer.wrap(outString.getBytes());
      fc1.write(buffer);
      fc1.close();
      f1.close();
    } catch (FileNotFoundException e) {
      // TODO 自动生成的 catch 块
      throw new Exception(e.toString());
    } catch (IOException e) {
      // TODO: handle exception
      throw new Exception(e.toString());
    }
    long endtime = System.currentTimeMillis();
    System.out.println("Channel策略写文件花费了:" + (endtime - starttime) + "ms");
  }
  
  public static void main(String[] args) {
    String outfilename = "src\\txt\\cd.txt";
    String outString = "This is channel strategy!";
    Channel myChannel = new Channel();
    try {
      myChannel.mywrite(outString, outfilename);
      System.out.println(myChannel.myread(outfilename));
    } catch (Exception e) {
      // TODO 自动生成的 catch 块
      e.printStackTrace();
    }
  }
}
           

运行结果

java文件读写之Channel策略