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行没阴影的部分)连接成一行,因为是先拼接成字节数组再转字符串,因此不会出现乱码的情况。



代码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. import java.io.File;  
  2. import java.io.IOException;  
  3. import java.io.RandomAccessFile;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.FileChannel;  
  6. import java.util.Date;  
  7.   
  8. public class TestNIO3 {  
  9.   
  10.     public static void main(String args[]) throws Exception {  
  11.   
  12.         int bufSize = 1000000;//一次读取的字节长度  
  13.         File fin = new File("D:\\test\\20151224_1375789.txt");//读取的文件  
  14.         File fout = new File("D:\\test\\111111111111111111.txt");//写出的文件  
  15.         Date startDate = new Date();  
  16.         FileChannel fcin = new RandomAccessFile(fin, "r").getChannel();  
  17.         ByteBuffer rBuffer = ByteBuffer.allocate(bufSize);  
  18.   
  19.         FileChannel fcout = new RandomAccessFile(fout, "rws").getChannel();  
  20.         ByteBuffer wBuffer = ByteBuffer.allocateDirect(bufSize);  
  21.   
  22.         readFileByLine(bufSize, fcin, rBuffer, fcout, wBuffer);  
  23.         Date endDate = new Date();  
  24.           
  25.         System.out.print(startDate+"|"+endDate);//测试执行时间  
  26.     }  
  27.   
  28.     public static void readFileByLine(int bufSize, FileChannel fcin,  
  29.             ByteBuffer rBuffer, FileChannel fcout, ByteBuffer wBuffer) {  
  30.         String enterStr = "\n";  
  31.         try {  
  32.             byte[] bs = new byte[bufSize];  
  33.             //temp:由于是按固定字节读取,在一次读取中,第一行和最后一行经常是不完整的行,因此定义此变量来存储上次的最后一行和这次的第一行的内容,  
  34.             //并将之连接成完成的一行,否则会出现汉字被拆分成2个字节,并被提前转换成字符串而乱码的问题,数组大小应大于文件中最长一行的字节数  
  35.             byte[] temp = new byte[500];  
  36.             while (fcin.read(rBuffer) != -1) {  
  37.                 int rSize = rBuffer.position();  
  38.                 rBuffer.rewind();  
  39.                 rBuffer.get(bs);  
  40.                 rBuffer.clear();  
  41.                   
  42.                 //windows下ascii值13、10是换行和回车,unix下ascii值10是换行  
  43.                 //从开头顺序遍历,找到第一个换行符  
  44.                 int startNum=0;  
  45.                 int length=0;  
  46.                 for(int i=0;i<rSize;i++){  
  47.                     if(bs[i]==10){//找到换行字符  
  48.                         startNum=i;  
  49.                         for(int k=0;k<500;k++){  
  50.                             if(temp[k]==0){//temp已经存储了上一次读取的最后一行,因此遍历找到空字符位置,继续存储此次的第一行内容,连接成完成一行  
  51.                                 length=i+k;  
  52.                                 for(int j=0;j<=i;j++){  
  53.                                     temp[k+j]=bs[j];  
  54.                                 }  
  55.                                 break;  
  56.                             }  
  57.                         }  
  58.                         break;  
  59.                     }  
  60.                 }  
  61.                 //将拼凑出来的完整的一行转换成字符串  
  62.                 String tempString1 = new String(temp, 0, length+1"GBK");  
  63.                 //清空temp数组  
  64.                 for(int i=0;i<temp.length;i++){  
  65.                     temp[i]=0;  
  66.                 }  
  67.                 //从末尾倒序遍历,找到第一个换行符  
  68.                 int endNum=0;  
  69.                 int k = 0;  
  70.                 for(int i=rSize-1;i>=0;i--){  
  71.                     if(bs[i]==10){  
  72.                         endNum=i;//记录最后一个换行符的位置  
  73.                         for(int j=i+1;j<rSize;j++){  
  74.                             temp[k++]=bs[j];//将此次读取的最后一行的不完整字节存储在temp数组,用来跟下一次读取的第一行拼接成完成一行  
  75.                             bs[j]=0;  
  76.                         }  
  77.                         break;  
  78.                     }  
  79.                 }  
  80.                 //去掉第一行和最后一行不完整的,将中间所有完整的行转换成字符串  
  81.                 String tempString2 = new String(bs, startNum+1, endNum-startNum, "GBK");  
  82.                   
  83.                 //拼接两个字符串  
  84.                 String tempString = tempString1 + tempString2;  
  85. //              System.out.print(tempString);  
  86.                   
  87.                 int fromIndex = 0;  
  88.                 int endIndex = 0;  
  89.                 while ((endIndex = tempString.indexOf(enterStr, fromIndex)) != -1) {  
  90.                     String line = tempString.substring(fromIndex, endIndex)+enterStr;//按行截取字符串  
  91.                     System.out.print(line);  
  92.                     //写入文件  
  93.                     writeFileByLine(fcout, wBuffer, line);  
  94.   
  95.                     fromIndex = endIndex + 1;  
  96.                 }  
  97.             }  
  98.         } catch (IOException e) {  
  99.             e.printStackTrace();  
  100.         }  
  101.     }  
  102.   
  103.     /** 
  104.      * 写到文件上 
  105.      * @param fcout 
  106.      * @param wBuffer 
  107.      * @param line 
  108.      */  
  109.     @SuppressWarnings("static-access")  
  110.     public static void writeFileByLine(FileChannel fcout, ByteBuffer wBuffer,  
  111.             String line) {  
  112.         try {  
  113.             fcout.write(wBuffer.wrap(line.getBytes("UTF-8")), fcout.size());  
  114.   
  115.         } catch (IOException e) {  
  116.             e.printStackTrace();  
  117.         }  
  118.     }  
  119. }  


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 牛奶喝多了想吐怎么办 运动过度后吐了怎么办 喝酒后反胃想吐怎么办 拔牙后反胃想吐怎么办 健身完恶心想吐怎么办 锻炼后头晕想吐怎么办 高三学生睡眠不好怎么办 狗狗精力太旺盛怎么办 新入职的同事比你厉害怎么办 银子弹鞋开胶了怎么办 我很笨脑子反应慢怎么办 学车脑子不好使怎么办 生完二胎脑子不好使怎么办 羽毛球鞋买小了怎么办 羽毛球鞋买大了怎么办 感觉自己脑子越来越笨了怎么办? 生完孩子后身体素质差怎么办 胃口太好越来越胖怎么办 心情一紧张心跳手抖怎么办 消防兵新兵连俯卧撑不够怎么办 cf枪王永久禁赛怎么办 换了手机号花呗怎么办 xp系统无限重启怎么办 魔域配置资源读取错误怎么办 魔域异地交易了怎么办 魔域手游宝宝亲密度不够怎么办 魔域手游怎么改密码忘了怎么办 魔域装备注灵怎么办 lol外服账号忘记了怎么办 美服lol下载慢怎么办 台服天堂2延迟怎么办 梦幻专用瑞兽没有泰山怎么办 冲错了游戏点券怎么办 新手玩联盟很菜怎么办 cf玩一会儿卡退怎么办 魔域先锋区封号了怎么办 吃了减肥药头疼怎么办 冬天没用完的霜怎么办 手表带起来大了怎么办 碰到舞警打人该怎么办 合租者偷了东西却没有证据怎么办