如题。具体情形是:我要读取一个大文本,于是每次读取一小部分(假设每次读取58kb),读取出来的形式是byte数组,然后再把byte数组转化为String。现在遇上的问题是一些特殊编码如unicode最开始读取到的58kb数据不是乱码,但是往后都是乱码了。经过查找资料得知,原因是unicode一个字符要占几个字节吧,由于我分块读取所以把分界点的字符拆开了,比如只读取了半个字符。应该这就是问题所在了吧。现在我考虑的办法是分析每块读取的byte数组最后长度为10的一部分如果没有半个字符就读完,如果有半个字符就归到下一块。只是我不知该如何区分,求助。或者你们觉得我的想法有错或者有更好的想法也可以提出来。编码类型现在考虑到的有UNICODE、UTF-16BE、UTF-16LE。值得注意的是现在我已经能判断这几种编码类型了,所以问题仅仅有以上所说的

解决方案 »

  1.   

    你对文件操作的根本目的是什么?
    如果可能,使用nio方便多了
      

  2.   

    我就是用nio   内存映射 我读取的是1Gb的文本   请大家不要管其他事了  这样子做都是别人的特殊要求你们自己当然不能理解了  因为你们不是本人   请帮一下忙
      

  3.   

    up  来几个大大讲解一下io只是吧 小弟一片空白与茫然之中 搜索引擎又不会搜索这么长的内容
      

  4.   

    分析每块读取的byte数组最后长度为10的一部分如果没有半个字符就读完,如果有半个字符就归到下一块。
    你得这种方法可能只能自己从底层编代码实现。非得读取出来的形式是byte数组吗?
    例如用BufferedReader.read(char[], int, int)方法读入到char数组不会出现“半个汉字”的问题。但是要自己控制读取的长度(比如58k)。如果不是一定要读取出到byte数组,用读入字符的方式,处理中西文混排的文本时不会有“半个汉字”的问题。
      

  5.   

    char数组也可以但是我不懂怎么把char数组指定编码变为String  
    还有就是英文unicode编码的也会出现乱码  
      

  6.   

    其实不仅是半个字符,包括1/3个字符、2/3个字符等,都是需要归入下一块的。
    如何将字符归入下一块,这是数组操作,楼主应该问题不大。
    如何判断字节数组是否残缺字符,楼主可以参照下面的代码: public static void main(String[] args){
    byte[] source = new byte[]{(byte)0xE4, (byte)0xB8, (byte)0xAD}; //中(UTF-8)
    byte[] source2 = new byte[]{(byte)0xE4, (byte)0xB8 };
    byte[] source3 = new byte[]{(byte)0xE4 };
    System.out.println( isValidChar(source, "UTF8")); //true
    System.out.println( isValidChar(source2, "UTF8"));  //false,残缺
    System.out.println( isValidChar(source3, "UTF8"));  //false,残缺
    }
    private static boolean isValidChar(byte[] bytes, String charset){
    boolean res = true;
    ByteBuffer bb = ByteBuffer.wrap(bytes);
    CharsetDecoder utf8Decoder =
          Charset.forName(charset).newDecoder().onMalformedInput(CodingErrorAction.REPORT);
    try{
    utf8Decoder.decode(bb);
    }catch(Exception e){
    res = false; 
    }
    return res;
    }
      

  7.   

    直接用字符流不就好了吗?如果你知道是utf8的话。
    http://docs.oracle.com/javase/tutorial/i18n/text/stream.html
      

  8.   


    用字符流读取时打开文件流时指定字符集,由char[]转换为String时不指定编码,String的值在JVM内都是unicode编码。
           /**
     * @param name 文件名。
     * @param charset 字符集。指定的字符集必须与name指定的文件的字符集一致,否则乱码。
     */
    public void readDemo(String name, String charset) {
    InputStreamReader instream = null; try {
    FileInputStream fis = new FileInputStream(name);
    instream = new InputStreamReader(fis, charset); int number;
    char[] cbuf = new char[80];
    // 示例,每次读入20个字符
    while ((number = instream.read(cbuf, 0, 20)) != -1) {
    String str = new String(cbuf, 0, number);
    System.out.println(str);
    }
    } catch (FileNotFoundException e) {
    // 处理异常...
    } catch (UnsupportedEncodingException e) {
    // 处理异常...
    } catch (IOException e) {
    // 处理异常...
    } finally {
    try {
    if (instream != null)
    instream.close();
    } catch (IOException e) {
    }
    }
    }
      

  9.   

    文本读取就不应该是byte[]数组了
    而是char[]
    InputStream实现用BufferedInputStreamchar[] -> String和byte没区别
    String的构造函数有
    String(char[],offset,size)
      

  10.   

    我用nio读取的  获得内存映射的实例用的是randomaccess  这两个都没有读取的时候指定charset的  由于现在的特殊要求暂时用nio来实时读取某一块内容
      

  11.   

    如果再考虑GB和UTF-8,那就难了。
    这种情况下,
    理论上你从文章中间找10个连续字节,判断出正确字符起点的可能性不大。

    abcdefghij
    可能ab cd ef gh ij是合法字符的同时bc de fg hi也是合法字符。这时,只有两个办法:
    ①从10个字节增加到1000个字节(举例),增加准确度,但依然不可能达到100%正确
    ②从前往后依次读取(也就是说,知道正确字符起点,仅需剔除结尾残字到下一块)但似乎不符合你的需求
      

  12.   

    GB和UTF-8非常明显就是变长的。每个字符的字节长度可能不一致。所以对齐是不可能的。依次判断每字节的高位码头的话,和干脆转换为字符相比不知道性能会差别多少,估计差别不大。实在不行,就依次读取各块,将块尾的残缺字符(通常1-3个字节)并入下块处理。
      

  13.   

    不错啊。记得测试下每种charset下不同的换行符字节序列啊,免得破坏换行符。
    还有考虑不同OS上的换行符不同的问题。
      

  14.   

    不好意思,仔细想了下,发现认换行符还是不行的,如以下UTF-16编码序列:
    0x53, 0, 0x0A, (byte)0xA0
    是两个合法Unicode字符“匀ઠ”
    但是其中0, 0x0A子串就是换行符。
    尽管这种字符组合基本不会出现,(Ops, 在我这个帖子中,它已经出现)
    但是这个例子让我放弃了对楼主想法的赞同。
      

  15.   


    呵呵 你多虑了。首先换行符是唯一的,即使亿分之一的概率出现和换行符字节相同的字符那也是没关系的。因为换行符不是必须的。1.首先残缺字符肯定是在结尾;2.残缺字符的字节数组中不可能包含换行符。
    所以我的方案是完美的。
    按照约定先奉上我的代码
    public int newLength(byte[] data,String charset){
    String lastStr=" \n";
    String nullStr=" ";
    byte[] array=null;
    byte[] nullByte=null;
    try {
    array=lastStr.getBytes(charset);
    nullByte=nullStr.getBytes(charset);

    } catch (UnsupportedEncodingException e) {
    }
    if(null!=array){
    boolean flag=true;
    int len1=data.length;
    int len2=array.length;
    byte[] temp=new byte[len2-nullByte.length];
    System.arraycopy(array, nullByte.length, temp, 0, temp.length);
    System.out.println("Array"+Arrays.toString(temp));
    len2=temp.length;
    int j=len2-1;
    for(int i=len1-1;i>-1;i--){
    flag=true;
    if(j>-1&&data[i]==temp[j]){
    j--;
    }
    else{
    flag=false;
    j=len2-1;
    }
    if(j==-1&&flag){
    array=null;
    nullByte=null;
    return i+len2;
    }
    }
    }
    array=null;
    nullByte=null;
    return data.length;
    }写得很罗嗦。我试了一下,结果第二页中英文不会出现乱码了(比之前好多了),但是中文出现乱码,翻回第一页正常。想不明白为什么,求各位大大赐教。难道说我的方案哪里还有漏洞么?还是代码写错了?
      

  16.   

    换行符可以不是必须的,但是错误识别出来的“换行符”前后被破坏的其他字符是否是必须的呢。
    如果你是任意切块,随机进入任意一块的话,残缺字符可能也出现在块的头部。
    OK,26楼所举例子确实是极端情况,不太会出现。怕的就是某日它真的出现了。就不和你讨论这个了,反正你也知道了。至于你的程序,
    你的nullStr和lastStr为什么都要包含一个空格呢?
      

  17.   

    第二页乱码问题,不知道你有没有确保data的起始是正确的,包括首字符不残缺,也包括FEFF前缀。
      

  18.   


    UNICODE、UTF-16BE、UTF-16LE 都是2byte一个字符
      

  19.   


    feff前缀是啥意思  还有就是我写错了 没想得到会遇上没匹配到换行符的情况  应该加个判断什么的
    哎  当时我太着急了 因为我几乎每次都遇上别人问我干啥的  为什么要那样做,我就急了 。况且世界上那么多人怎么能都问呢  而且无奇不有是不是?很多情况是我们想不到的  因为不是当事人啊
      

  20.   

    UTF-16编码的前缀啊。你程序中不是体现到你知道这一点的嘛。
      

  21.   

    11楼的代码不能实现你的需求吗?建议你停下来去看看JDK源码,你会发现读取不同字符集的文件是怎么实现的。你似乎很执着,非得读到byte[]检测“半个字符”之类。先前我在7L说了,按你的思路,要自己编写代码从底层实现,例如你读入58K到byte[],得从byte[]起始处检测,其实JDK现成的方法也是这么干的,你这么绕来绕去的,何不直接用它给你提供的现成的方法呢?涉及这些比较底层的东西,停下来去看看JDK相应的源码比较好。如果你不能确保写出比它更好的实现代码,还是用它给你提供的现成的方法比较好一点。
      

  22.   


    首先 我可能必须要读取为byte了  因为我提供了一个功能 允许用户随时更改编码格式  我不是把string。getbyte的  而是使用当前缓存的byte数组来允许用户任意构造任意编码的text 这样能确保准确与快速  其次我用到了MappedByteBuffer来很方便很快速地任意读取某一块内容的   输入流要求有getChannel()这个方法才能获得MappedByteBuffer的实例。 
      

  23.   

    详情请看  这个是我做的 那个东西留着很多bug没解决  现在只剩下这个大bug没解决了 不解决都不好意思更新了http://www.anzhi.com/soft_84133.html
      

  24.   

    FileInputStream stream = new FileInputStream("filepath");
    String charsetName = "utf-8";
    InputStreamReader reader = InputStreamReader(stream , String charsetName);
    BufferedReader in = new BufferedReader(reader);
    while((String line = in.readLine())!=null){
    ...
    }
    in.close();
    stream.close();
      

  25.   

    用字符流,str.toCharArray().length<str.getBytes().length,说明存在占两个字节的中文或其它字符,那你就需要一个个排查,再分开它们了了