问题描述
我正在尝试编写一个代码,该代码根据用户输入的索引从文件中提取单词,但是问题是来自readChar()
类的方法RandomAccessFile
正在返回日语字符,我必须承认这不是我第一次在lenovo笔记本电脑上看到它,有时在某些安装向导中,我可以看到带有普通字符和日语字符混合的东西,您认为它来自笔记本电脑还是而不是代码?
这是代码:
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
是偶数;如果是奇数,则一定要放在一个char的中间,从而读取垃圾。
i
从零开始,但您增加了1,即半个字符。
您的搜索参数应该为(2*(N-1+i))
。
另一种解释:您的文件根本不包含chars
;例如,您创建了一个ASCII文件,其中一个字符是一个字节。
在这种情况下,错误是试图使用readChar
函数读取ASCII(过时的字符编码)。
但是,如果文件包含ASCII,则在seek参数中乘以2的目的是模糊的。它显然没有任何用处。
,有很多错误,都与基本的误解有关。
首先:磁盘上的文件-不用担心Java或任何其他编程语言中的File
接口;文件本身-也不会存储文本。曾经它存储字节。也就是说,原始数据(在数十年来一直与之相关的每台机器上,但是历史上还有其他方法可以做到)以位为单位进行量化,这些数据被分为8组,称为字节。
文本是一种抽象;对某些特殊的字节值序列的解释。从根本上和不可避免地,它取决于 encoding 。由于这不是博客,因此我将在这里为您保留历史课程,但是足以说明Java的char
类型不会不只是存储文本字符。它存储一个无符号的两个字节的值,其中可能表示文本字符。因为Unicode中的文本字符多于两个字节可以表示的字符,所以有时需要数组中两个相邻的char
来表示文本字符。 (并且,当然,那里可能存在滥用char
类型的代码,仅仅是因为有人想要与short
等价的无符号等效物。我什至可能已经写了一些自己的东西。那个时代对我来说是一个模糊的时期。 )
无论如何,关键是:使用.readChar()
将从文件中读取两个字节,并将它们存储到char
中的char[]
中,而相应的数值不是将会类似于您想要的东西-除非您的文件会使用与Java本机使用的相同编码(称为UTF-16)进行编码。
在 不知道 的情况下,您 不能正确读取和解释文件。句号您最多只能自欺欺人以为自己可以阅读。您还 不能 具有对文本文件的“随机访问”权限-即,根据文本的字符数编制索引-除非所涉及的编码为恒定宽度。 (当然,否则,您不能只计算给定文本字符到文件的字节距离;这取决于前一个字符占用了多少字节,还取决于它们是哪个字符。)许多文本编码的宽度不是恒定的。坦率地说,One of the most popular并不是当今大多数任务的默认默认建议。在这种情况下,您根本就不了解所描述的问题。
无论如何,一旦您知道文件的编码,从Java中的文件中检索文本字符的预期方式就是使用Reader类之一,例如InputStreamReader:
InputStreamReader是从字节流到字符流的桥梁:它读取字节,并使用指定的字符集将其解码为字符。它使用的字符集可以按名称指定,也可以明确指定,也可以接受平台的默认字符集。
(这里charset
仅表示Java用于表示文本编码的类的实例。)
您 也许 可以稍微弄乱您的问题描述:寻求字节偏移量,然后从该偏移量开始获取文本字符。但是,不能保证“从该偏移量开始的文本字符”是有意义的,或者实际上可以完全解码。如果偏移量恰好在字符的多字节编码中间,则其余部分不一定是有效的编码文本。
,我将文件的编码更改为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();
}
}