package com.chah.io;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* NIO读取百万级别文件
*
* @author Chillax
*
*/
public class NIO {
public static void main(String args[]) throws Exception {
int bufSize = 1000000;// 一次读取的字节长度
File fin = new File("D:\\tmp\\logs\\qyh-CC.log");// 读取的文件
// File fout = new File("D:\\test\\20160622_627975_1.txt");// 写出的文件
Date startDate = new Date();
FileChannel fcin = new RandomAccessFile(fin, "r").getChannel();
ByteBuffer rBuffer = ByteBuffer.allocate(bufSize);
// FileChannel fcout = new RandomAccessFile(fout, "rws").getChannel();
ByteBuffer wBuffer = ByteBuffer.allocateDirect(bufSize);
// readFileByLine(bufSize, fcin, rBuffer, fcout, wBuffer);
readFileByLine(bufSize, fcin, rBuffer, null, wBuffer);
Date endDate = new Date();
System.out.print(startDate + "|" + endDate);// 测试执行时间
if (fcin.isOpen()) {
fcin.close();
}
// if (fcout.isOpen()) {
// fcout.close();
// }
}
public static void readFileByLine(int bufSize, FileChannel fcin, ByteBuffer rBuffer, FileChannel fcout,
ByteBuffer wBuffer) {
String enter = "\n";
List<String> dataList = new ArrayList<String>();// 存储读取的每行数据
byte[] lineByte = new byte[0];
// String encode = "GBK";
String encode = "UTF-8";
try {
// temp:由于是按固定字节读取,在一次读取中,第一行和最后一行经常是不完整的行,因此定义此变量来存储上次的最后一行和这次的第一行的内容,
// 并将之连接成完成的一行,否则会出现汉字被拆分成2个字节,并被提前转换成字符串而乱码的问题
byte[] temp = new byte[0];
while (fcin.read(rBuffer) != -1) {// fcin.read(rBuffer):从文件管道读取内容到缓冲区(rBuffer)
int rSize = rBuffer.position();// 读取结束后的位置,相当于读取的长度
byte[] bs = new byte[rSize];// 用来存放读取的内容的数组
rBuffer.rewind();// 将position设回0,所以你可以重读Buffer中的所有数据,此处如果不设置,无法使用下面的get方法
rBuffer.get(bs);// 相当于rBuffer.get(bs,0,bs.length()):从position初始位置开始相对读,读bs.length个byte,并写入bs[0]到bs[bs.length-1]的区域
rBuffer.clear();
int startNum = 0;
int LF = 10;// 换行符
int CR = 13;// 回车符
boolean hasLF = false;// 是否有换行符
for (int i = 0; i < rSize; i++) {
if (bs[i] == LF) {
hasLF = true;
int tempNum = temp.length;
int lineNum = i - startNum;
lineByte = new byte[tempNum + lineNum];// 数组大小已经去掉换行符
System.arraycopy(temp, 0, lineByte, 0, tempNum);// 填充了lineByte[0]~lineByte[tempNum-1]
temp = new byte[0];
System.arraycopy(bs, startNum, lineByte, tempNum, lineNum);// 填充lineByte[tempNum]~lineByte[tempNum+lineNum-1]
String line = new String(lineByte, 0, lineByte.length, encode);// 一行完整的字符串(过滤了换行和回车)
dataList.add(line);
System.out.println(line);
// writeFileByLine(fcout, wBuffer, line + enter);
// 过滤回车符和换行符
if (i + 1 < rSize && bs[i + 1] == CR) {
startNum = i + 2;
} else {
startNum = i + 1;
}
}
}
if (hasLF) {
temp = new byte[bs.length - startNum];
System.arraycopy(bs, startNum, temp, 0, temp.length);
} else {// 兼容单次读取的内容不足一行的情况
byte[] toTemp = new byte[temp.length + bs.length];
System.arraycopy(temp, 0, toTemp, 0, temp.length);
System.arraycopy(bs, 0, toTemp, temp.length, bs.length);
temp = toTemp;
}
}
if (temp != null && temp.length > 0) {// 兼容文件最后一行没有换行的情况
String line = new String(temp, 0, temp.length, encode);
dataList.add(line);
System.out.println(line);
// writeFileByLine(fcout, wBuffer, line + enter);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 写到文件上
*
* @param fcout
* @param wBuffer
* @param line
*/
@SuppressWarnings("static-access")
public static void writeFileByLine(FileChannel fcout, ByteBuffer wBuffer, String line) {
try {
fcout.write(wBuffer.wrap(line.getBytes("UTF-8")), fcout.size());
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO 读写
最新推荐文章于 2022-11-23 18:05:44 发布