定义:
FileChannel是Java NIO对应于磁盘等存储设备文件操作的通道。
常用API详解:
获取FileChannel的API
/**
* 打开一个与文件的连接通道,用于进行文件操作。
* path:path,文件的路径对象,可用Path.get("文件路径"),获取。
* options:通道的操作参数。通常使用实现类枚举StandardOpenOption指定。
* attrs:创建文件时自动设置的文件属性的可选列表,比如读写执行。
*/
public static FileChannel open(Path path,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs);
//打开一个与文件的连接通道,用于进行文件操作。并可以设置通道的操作参数options
public static FileChannel open(Path path, OpenOption... options)
demo:
public class FileChannelDemo {
public static void main(String[] args) throws IOException {
//以读和写的方式打开与文件555.txt的连接的通道。
FileChannel fileChannel = FileChannel.open(Paths.get("555.txt"),StandardOpenOption.READ,
StandardOpenOption.WRITE);
//
Set<OpenOption> openOptions = new HashSet<>();
openOptions.add(StandardOpenOption.CREATE);
openOptions.add(StandardOpenOption.READ);
openOptions.add(StandardOpenOption.WRITE);
Set<PosixFilePermission> fileAttributes = new HashSet<>();
fileAttributes.add(PosixFilePermission.OWNER_READ);
fileAttributes.add(PosixFilePermission.OWNER_WRITE);
fileAttributes.add(PosixFilePermission.OWNER_EXECUTE);
//以读和写和创建并打开与文件666.txt的连接的通道。并且创建的文件会赋予文件所属者读写执行的权限。
FileChannel fileChannel1 = FileChannel.open(Paths.get("666.txt"),openOptions,
PosixFilePermissions.asFileAttribute(fileAttributes));
}
}
Java NIO学习篇之StandardOpenOption详解
Java NIO学习篇之StandardOpenOption详解
读写API:
//把文件数据通过通道读取到缓冲区dst中。返回读取到数据长度。返回-1表示到达文件尾。
public abstract int read(ByteBuffer dst) throws IOException;
//把文件数据通过通道读取到缓冲区数组dst中。返回读取到数据长度。返回-1表示到达文件尾。
//会依次读取到缓冲区数组中的缓冲区,知道把数据读完或者缓冲区不够大。
public final long read(ByteBuffer[] dsts) throws IOException;
//把文件数据通过通道读取到缓冲区数组dst中。返回读取到数据长度。返回-1表示到达文件尾。
//会依次读取到缓冲区数组中的缓冲区,知道把数据读完或者缓冲区不够大。
//可以设置读取到缓冲区数组中的哪些数组,假如dsts数组有5个缓冲区,offset=1 length=3,
//则只会把数据读取到缓冲区数组的下标 1,2,3三个缓冲区上,offset代表下标,length代表长度
public abstract long read(ByteBuffer[] dsts, int offset, int length);
//把文件数据通过通道读取到缓冲区数组dst中。
//以上的读取数组方法读取一个字节数据FileChannel中的游标会右移一位,但是这个方法不会移动游标。
//也就是重复读取还是读取那些数据。
public abstract int read(ByteBuffer dst, long position) throws IOException;
demo:
public static void testRead() throws IOException {
FileChannel fileChannel = FileChannel.open(Paths.get("5555.txt"),StandardOpenOption.READ);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
System.out.println("==================>>read(ByteBuffer dst)<<=====================");
//读取时从文件的总数据字节第二位开始读取
fileChannel.read(byteBuffer,1);
byteBuffer.flip();
System.out.println("position = " + fileChannel.position());
System.out.println(new String(byteBuffer.array()));
byteBuffer.clear();
System.out.println("==================>>read(ByteBuffer dst, long position)<<=====================");
fileChannel.read(byteBuffer);
byteBuffer.flip();
System.out.println("position = " + fileChannel.position());
System.out.println(new String(byteBuffer.array()));
}
结果:
文件内容:
解释:
第一个读取时使用read(ByteBuffer dst, long position)方法进行读取,position设置为1,所以文件的第一个字节数据I被跳过了。并且读完后通道的偏移量仍然为0。
//把缓冲区中的position到limit-1的数据通过通道写到文件中去。返回写的数据长度。
public abstract int write(ByteBuffer src) throws IOException;
//把缓冲区数组中的多个缓冲区依次通过管道写到文件中去,offset与length与read对应方法大致。
public abstract long write(ByteBuffer[] srcs, int offset, int length)
//把缓冲区数组中的多个缓冲区依次通过管道写到文件中去。
public final long write(ByteBuffer[] srcs) throws IOException
//读取缓冲区的数组通过通道写到文件中去,可指定读取缓冲区的position偏移量。假如缓冲区当前
//position为0,position参数为1,那么最终缓冲区数据读取0+1 到limit-1 的数据。
public abstract int write(ByteBuffer src, long position) throws IOException;
其他API:
//关闭通道
public final void close();
//返回文件的大小
public abstract long size() throws IOException;
//返回此文件字节数据的偏移量。
public abstract long position();
//设置此文件字节数据的偏移量。如果设置地比文件大size大,就会在读取时读到文件尾。返回-1.
public abstract FileChannel position(long newPosition)
//强制将数据刷到存储设备上,如果metaData为false只刷数据,如果metaData为true,刷数据与元数据(权限等)
public abstract void force(boolean metaData);
//判断通道是否还打开着,没有关闭。
public final boolean isOpen();
//返回一个直接缓冲区MappedByteBuffer
//mode设置直接缓冲区的权限。
//position从通道的文件数据游标position开始。
//size表示要写到缓冲区的数据的长度
public abstract MappedByteBuffer map(MapMode mode,
long position, long size)
throws IOException;
public static class MapMode {
/**
* 只读模式
*/
public static final MapMode READ_ONLY
= new MapMode("READ_ONLY");
/**
* 读写模式
*/
public static final MapMode READ_WRITE
= new MapMode("READ_WRITE");
/**
* 写时复制模式
*/
public static final MapMode PRIVATE
= new MapMode("PRIVATE");
private final String name;
private MapMode(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
使用MappedByteBuffer 实现文件复制:
public static void testMapMode() throws IOException {
FileChannel readFileChannel = FileChannel.open(Paths.get("5555.txt"),StandardOpenOption.READ);
FileChannel writeFileChannel = FileChannel.open(Paths.get("5555_copy.txt"),StandardOpenOption.READ,StandardOpenOption.WRITE,
StandardOpenOption.CREATE_NEW);
MappedByteBuffer readMap = readFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, readFileChannel.size());
MappedByteBuffer writeMap = writeFileChannel.map(FileChannel.MapMode.READ_WRITE,0,readFileChannel.size());
byte[] array = new byte[readMap.remaining()];
readMap.get(array);
//无需通道直接进行文件写
writeMap.put(array);
writeFileChannel.close();
readFileChannel.close();
}
transferTo和transferFrom
/**
* 把本通道打开的文件的数据传输到目标通道target中。
* 可以指定本通道的position文件数据游标和要传输的数据大小size。如果position比本通道打开的文件大,就没有字节转移。
* 传输是使用直接内存以零拷贝的方式进行传输。
* 该传输不会改变本通道的position值。
*/
public abstract long transferTo(long position, long count,
WritableByteChannel target)
throws IOException;
/**
* 把src通道打开的文件的数据传输到本通道中
* 可以指定转移写入的本通道的文件的position位置,和要转移的数据长度size。如果position比本通道打开的文件大,就没有字节转移。
* 传输是使用直接内存以零拷贝的方式进行传输。
* 该传输不会改变src通道的position值
*/
public abstract long transferFrom(ReadableByteChannel src,
long position, long count)
throws IOException;
demo:
public static void testTransfer() throws IOException {
FileChannel readFileChannel = FileChannel.open(Paths.get("5555.txt"),StandardOpenOption.READ);
//把文件5555复制一份 6666.txt
FileChannel writeFileChannel = FileChannel.open(Paths.get("6666.txt"),StandardOpenOption.CREATE,StandardOpenOption.WRITE);
readFileChannel.transferTo(0,readFileChannel.size(),writeFileChannel);
//把文件5555复制一份 7777.txt
FileChannel rfc = FileChannel.open(Paths.get("7777.txt"),StandardOpenOption.CREATE,StandardOpenOption.WRITE);
rfc.transferFrom(readFileChannel,0,readFileChannel.size());
}