zoukankan      html  css  js  c++  java
  • JAVA使用NIO技术按行读写大文件并且完美解决中文乱码问题

    假设我们一次读取的字节是从下图的start到end,因为结尾是汉字,所以有几率出现上述的情况。

    解决方法如下:将第9行这半行(第9行阴影的部分)跟上一次读取留下来的半行(第9行没阴影的部分)按顺序存放在字节数组,然后转成字符串;中间第10行到第17行正常转换成字符串;第18行这半行(第18行阴影的部分)留着跟下一次读取的第1行(第18行没阴影的部分)连接成一行,因为是先拼接成字节数组再转字符串,因此不会出现乱码的情况。

    package com.chillax.imp;  
      
    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:\test\20160622_627975.txt");//读取的文件  
            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);  
            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 = "
    ";  
            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();  
            }  
        }  
    }  
  • 相关阅读:
    VS2010 自动跳过代码现象
    Reverse Linked List II 【纠结逆序!!!】
    Intersection of Two Linked Lists
    Linked List Cycle II
    Remove Nth Node From End of List 【另一个技巧,指针的指针】
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Remove Duplicates from Sorted List
    Linked List Cycle
    Dungeon Game
  • 原文地址:https://www.cnblogs.com/cnndevelop/p/12197363.html
Copyright © 2011-2022 走看看