readChar() 方法显示日文字符

The readChar() method displays japanese character

我正在尝试编写一个代码,根据用户输入的索引从文件中提取单词,但问题是 readChar() 来自 RandomAccessFile class 正在返回日文字符,我必须承认这不是我第一次在我的联想笔记本电脑上看到这个,有时在一些安装向导中我可以看到混合的东西,普通字符和日文字符混合在一起,你认为它来自笔记本电脑还是来自代码?

这是代码:

package com.project;

import java.io.*;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) throws IOException {
        int N, i=0;
        char C;
        char[] charArray = new char[100];
        String fileLocation = "file.txt";
        BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
        do {
            System.out.println("enter the index of the word");
            N = Integer.parseInt(buffer.readLine());
            if (N!=0) {
                RandomAccessFile word = new RandomAccessFile(new File(fileLocation), "r");
                do {
                    word.seek((2*(N-1))+i);
                    C = word.readChar();
                    charArray[i] = C;
                    i++;
                }while(charArray[i-1] != ' ');
                System.out.println("the word of index " + N + " is: " );
                for (char carTemp : charArray )
                System.out.print(carTemp);
                System.out.print("\n");

            }
        }while(N!=0);
        buffer.close();
    }
}

我得到这个输出:

瑯潕啰灰灥敲牃䍡慳獥攨⠩⤍ഊੴ瑯潌䱯潷睥敲牃䍡慳獥攨⠩⤍ഊ੣捯潭浣捡慴琨⡓却瑲物楮湧朩⤍ഊ੣捨桡慲牁䅴琨⡩楮湴琩⤍ഊੳ獵畢扳獴瑲物楮湧木⠠⁳獴瑡慲牴琠⁩楮湤摥數砬Ⱐ⁥敮湤搠⁩楮湤摥數砩⤍ഊੴ瑲物業洨⠩Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 100 out of bounds for length 100
    at Main.main(Main.java:21)

char为16位,即2字节。

seek 寻找字节边界。

如果文件包含字符,则它们的偏移量为偶数:0、2、4...

表达式 (2*(N-1))+i) 是偶数当且仅当 i 是偶数;如果奇数,你肯定会落在一个字符的中间,从而读取垃圾。

i 从零开始,但你递增 1,即半个字符。

您的搜索参数可能应该是 (2*(N-1+i))


另一种解释:您的文件根本不包含chars;例如,您创建了一个 ASCII 文件,其中一个字符是一个字节。

在这种情况下,错误是试图使用 readChar 函数读取 ASCII(一种过时的字符编码)。

但是如果文件包含 ASCII,则在 seek 参数中乘以 2 的目的就不清楚了。它显然没有任何用处。

错误的地方有很多,所有这些都与基本的错误观念有关。

首先:磁盘上的一个文件 - 别管 Java 或任何其他编程语言中的 File 界面;文件本身 - 不会也不能存储文本。曾经。它存储字节。也就是说,原始数据(在几十年来一直相关的每台机器上,但历史上还有其他方法可以做到这一点)以比特为单位进行量化,这些比特被组织成 8 组,称为字节。

文本是一种抽象; 某些特定字节值序列的解释。它从根本上和不可避免地取决于 编码 。因为这不是博客,所以我会在这里给你上历史课,但足以说明 Java 的 char 类型 而不是 只是存储文本字符。它存储一个无符号two-byte值可能表示一个文本字符。因为 Unicode 中文本的字符多于两个字节所能表示的,所以有时需要数组中相邻的两个 char 来表示一个文本字符。 (当然,可能存在滥用 char 类型的代码,仅仅是因为有人想要 short 的无符号等价物。我什至可能自己写了一些。那个时代对我来说是模糊的.)

总之,重点是:使用.readChar()会从你的文件中读取两个字节,并将它们存储到你的char[]中的char中,以及相应的数值不会像您想要的那样 - 除非您的文件 碰巧 使用 Java 本地使用的相同编码进行编码,称为 UTF-16。 =23=]

无法不知情的情况下正确阅读和解释文件 文件编码。句号。您充其量只能自欺欺人地相信自己可以阅读它。您还 不能 对文本文件进行“随机访问”——即根据文本的字符数进行索引——除非有问题的编码是恒定宽度。 (否则,当然,您不能只将 distance-in-bytes 计算到给定文本字符所在的文件中;这取决于前面的字符占用了多少字节,这取决于它们是什么字符。)许多文本编码的宽度不是恒定的。 One of the most popular,坦率地说,这是当今大多数任务的合理默认建议,但事实并非如此。在这种情况下,您所描述的问题只是运气不好。

无论如何,一旦您知道文件的编码,从 Java 中的文件检索文本字符的预期方法是使用 Reader classes,例如InputStreamReader:

An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.

(此处,charset 仅表示 Java 用于表示文本编码的 class 的一个实例。)

可能可以稍微捏造你的问题描述:寻找一个字节偏移量,然后抓取文本字符从那个偏移量开始。但是,不能保证“从那个偏移量开始的文本字符”有任何意义,或者实际上可以被解码。如果偏移量恰好位于字符 multi-byte 编码的中间,则剩余部分不一定是有效的编码文本。

我将文件的编码更改为 UTF-16 并修改了程序以显示正确的索引,那些代表每个单词的开头,现在可以正常工作了,谢谢大家。

  import java.io.*;

public class Main {
public static void main(String[] args) throws IOException {
    int N, i=0, j=0, k=0;
    char C;
    char[] charArray = new char[100];
    String fileLocation = "file.txt";
    BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
    DataInputStream in = new DataInputStream(new FileInputStream(fileLocation));
    boolean EOF=false;
    do {
        try {
            j++;
            C = in.readChar();
           if((C==' ')||(C=='\n')){
                System.out.print(j+1+"\t");
            }

        }catch (IOException e){
            EOF=true;
        }

    }while (EOF!=true);
    System.out.println("\n");
    do {
        System.out.println("enter the index of the word");
        N = Integer.parseInt(buffer.readLine());
        if (N!=0) {
            RandomAccessFile word = new RandomAccessFile(new File(fileLocation), "r");


            do {

                word.seek((2*(N-1+i)));
                C = word.readChar();
                charArray[i] = C;
                i++;
            }while(charArray[i-1] != ' ' && charArray[i-1] != '\n');
            System.out.print("the word of index " + N + " is: " );
            for (char carTemp : charArray )
                System.out.print(carTemp);
            System.out.print("\n");
             i=0;
            charArray = new char[100];
        }
    }while(N!=0);
    buffer.close();


   }
}