NIO:
- 通道 read write
- 缓冲区 put get
- 字符集
- 选择器
- Path接口
- Files工具类
- BasicFileAttributes文件属性类
/*
* NIO:不是替代IO,是对IO的一种补充,可以更精细的管控流和访问文件系统
*
* 通道 : 读取/写入流的通道类 getChannel()方法 支持通道的类有:FileInputStream
* FileOutputStream Socket 常用方法有:读read() 写write()
* 缓冲区:依托通道--从流中读出的内容可放置缓冲区,缓冲区内的内容可写入流,常用缓冲区
* ByteBuffer ...等对应7种基本类型的,以及 MappedByteBuffer用于将文件映射
* 到缓冲区,缓冲区的三大要素:当前位置、界限、容量。常用方法有:
* 容量capacity() 清空clear() 位置position() 重置rewind() 界限limit()
* 写put() 读get() 分配allocate() 切分slice()
* 字符集:依托字符集,将字节映射成字符 例如:UTF-8 GBK
* 选择器:适用于套接字的通道,使用选择器可以通过多个通道执行IO
*/
/**
* jdk7 增加了Path Files BasicFileAttributes
*
* Path接口:封装了路径,提供了操作路径的大量方法. Path的toFile()<-互转->File的toPath()
* 获取Path的方法:Paths.get(String pathname,String...parts); Paths.get(URI uri);
*
* Files工具类:更加细腻的管控文件的大量方法.
* 常用方法有:
* 删除delete() 创建目录createDirectory() 创建文件createFile() 是否存在exists()
* 是否目录isDirectory() 是否文件isRegularFile() 文件大小size()
* 文件属性readAttributes() 是否可读isReadable() 是否可写isWritable()
* 是否隐藏的isHidden() 是否可执行的isExecutable() 文件拷贝copy() 文件移动move()
* 文件的流对象newInputStream() newOutputStream() 获取文件通道newByteChannel()
*
* OpenOption文件打开时的一些选项:枚举值有:APPEND追加写入
* CREATE_NEW文件不存在时就创建
* CREATE老文件要有就干掉,创建新的
*
* jdk8中该类新增4个方法 list() walk() lines() find() 都返回Stream流
*
* 文件属性类:BasicFileAttributes 常用方法有:
* 文件创建时间createTime() 是否目录isDirectory()
* 文件最后修改时间lastModifiedTime() 是否文件isRegularFile()
* 文件最后访问时间lastAccessTime() 文件大小size()
*/
/**
* BufferUnderflowException BufferOverflowException 错误原因:读取的长度超出了允许的长度
*
* 例如下面的代码:
* ByteBuffer buf = ByteBuffer.allocate(2); /这里只分配了2个字节
* buf.order(ByteOrder.LITTLE_ENDIAN);
* byte[] tmp = new byte[3];
* buf.get(tmp); //这里get了3个字节的数据,java.nio.BufferUnderflowException异常
*
* 如何解决这个问题呢?添加读取长度与 ByteBuffer 中可读取的长度的判断:例如:
* while (buf.remaining() > 0) { //每次读1个字节,就判断大于0;每次读2个字节,就判断大于1
* byte b = buf.get();
* }
*
* 总结:
* 当 ByteBuffer.remaining() 小于要读取或写入的长度时,再执行读取或写入操作都会产生异常;
* 读取则产生 java.nio.BufferUnderflowException 异常
* 写入则产生 java.nio.BufferOverflowException 异常
* 当 ByteBuffer.remaining()==0 时,不能再执行读取或写入操作
*/
/**
* \r 回车键 十进制表示为13 十六进制0x0D
* \n 换行键 十进制表示为10 十六进制0x0A
* windows系统 文件内容中的换行是\r\n
* unix系统 文件内容中的换行是/n
* mac系统 文件内容中的换行是/r
*/
/**
* 基于通道读文件
* 一般步骤:
* a:封装Path
* b:获取通道getChannel(path)
* c:准备缓冲区Buffer
* d:通过通道读写文件fChannel.read(buf); fChannel.write(buf);
*/
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.*;
//测试
public class NIOdemo
{
/**
* 通过缓冲区以及通道,实现读文件(读ISO8859-1格式的文件可以,读UTF/GBK格式保存的文件很麻烦)
*/
public static void readFileByByteBufferAndChannel(){
int count=0; //读写缓冲区时,缓冲区内部的游标不停的向前滚动,表示已经读到了多少个字节
int j=0; //第几次缓冲区已满
try(SeekableByteChannel fchan = Files.newByteChannel(Paths.get("test.txt")) ){ //获取通道
/*举例: 假定当前测试文件保存20个英文字母,系统默认ASNI编码格式,两行数据保存的. windows下换行时有(回车)(换行)两个字节,所以内容大小22
System.out.println("test.txt文件的内容:0123456789\\r\\naaaaaaaaaa (文件的大小:"+fchan.size()+") 其中: \\r回车一个字节 \\n换行一个字节");
System.out.println("文件内容windows下分成两行保存的,采用ASNI编码格式,如下:");
System.out.println("0123456789");
System.out.println("aaaaaaaaaa");
*/
long fSize = fchan.size();
String fileEncoding = judgeFileEncoding();
ByteBuffer buf = ByteBuffer.allocate(10); //准备缓冲区
byte[] tmpB = new byte[2]; //临时存放中文字符截断的前序字节(编码不同,有可能前序就1个字节,也有可能前序2个字节)
int k = 0; //计数器:临时保存上一字节的次数
/**
* buf.rewind()方法:为什么使用?因为想游标重置后,从缓冲区头开始干活(对buf的读/写都是时刻往后滚动游标的)
*/
do{
++j; //第几次从文件流读至缓冲区
buf.rewind(); //buf重置游标,归零处,为了从缓冲区头开始写
count = fchan.read(buf);
//System.out.println("\r\n当前第("+j+"