JAVA之NIO按行读写大文件,完美解决中文乱码问题
来源:互联网 发布:newsql数据库哪个最好 编辑:程序博客网 时间:2024/05/22 14:57
JAVA之NIO按行读写大文件,完美解决中文乱码问题
转载URL : http://blog.csdn.net/v123411739/article/details/50620289
前言
最近在开发的时候,接到了一个开发任务,要将百万行级别的txt数据插入到数据库中,由于内存方面的原因,因此不可能一次读取所有内容,后来在网上找到了解决方法,可以使用NIO技术来处理,于是找到了这篇文章http://www.sharejs.com/codes/java/1334,后来在试验过程中发现了一点小bug,由于是按字节读取,汉字又是2个字节,因此会出现汉字读取“一半”导致乱码的情况,于是花了几天时间将这个问题解决了。
例子
假设我们一次读取的字节是从下图的start到end,因为结尾是汉字,所以有几率出现上述的情况。
解决方法如下:将第9行这半行(第9行阴影的部分)跟上一次读取留下来的半行(第9行没阴影的部分)按顺序存放在字节数组,然后转成字符串;中间第10行到第17行正常转换成字符串;第18行这半行(第18行阴影的部分)留着跟下一次读取的第1行(第18行没阴影的部分)连接成一行,因为是先拼接成字节数组再转字符串,因此不会出现乱码的情况。
代码
- import java.io.File;
- import java.io.IOException;
- import java.io.RandomAccessFile;
- import java.nio.ByteBuffer;
- import java.nio.channels.FileChannel;
- import java.util.Date;
-
- public class TestNIO3 {
-
- public static void main(String args[]) throws Exception {
-
- int bufSize = 1000000;
- File fin = new File("D:\\test\\20151224_1375789.txt");
- File fout = new File("D:\\test\\111111111111111111.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);
- Date endDate = new Date();
-
- System.out.print(startDate+"|"+endDate);
- }
-
- public static void readFileByLine(int bufSize, FileChannel fcin,
- ByteBuffer rBuffer, FileChannel fcout, ByteBuffer wBuffer) {
- String enterStr = "\n";
- try {
- byte[] bs = new byte[bufSize];
-
-
- byte[] temp = new byte[500];
- while (fcin.read(rBuffer) != -1) {
- int rSize = rBuffer.position();
- rBuffer.rewind();
- rBuffer.get(bs);
- rBuffer.clear();
-
-
-
- int startNum=0;
- int length=0;
- for(int i=0;i<rSize;i++){
- if(bs[i]==10){
- startNum=i;
- for(int k=0;k<500;k++){
- if(temp[k]==0){
- length=i+k;
- for(int j=0;j<=i;j++){
- temp[k+j]=bs[j];
- }
- break;
- }
- }
- break;
- }
- }
-
- String tempString1 = new String(temp, 0, length+1, "GBK");
-
- for(int i=0;i<temp.length;i++){
- temp[i]=0;
- }
-
- int endNum=0;
- int k = 0;
- for(int i=rSize-1;i>=0;i--){
- if(bs[i]==10){
- endNum=i;
- for(int j=i+1;j<rSize;j++){
- temp[k++]=bs[j];
- bs[j]=0;
- }
- break;
- }
- }
-
- String tempString2 = new String(bs, startNum+1, endNum-startNum, "GBK");
-
-
- String tempString = tempString1 + tempString2;
-
-
- int fromIndex = 0;
- int endIndex = 0;
- while ((endIndex = tempString.indexOf(enterStr, fromIndex)) != -1) {
- String line = tempString.substring(fromIndex, endIndex)+enterStr;
- System.out.print(line);
-
- writeFileByLine(fcout, wBuffer, line);
-
- fromIndex = endIndex + 1;
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
-
-
-
-
-
-
- @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();
- }
- }
- }
0 0