问题描述
我遇到了来自用户的输入问题。我需要将用户的输入保存到二进制文件中,当我读取它并将其显示在屏幕上时,它无法正常工作。我不想放几百行,所以我会尽量用更紧凑的形式来描述它。项目属性中 NetBeans 中的编码为“UTF-8”
我在 NetBeans 控制台或 cmd 控制台中收到了来自用户的输入。然后我将它保存到由字符串组成的对象中,然后将它添加到 ArrayList<Ksiazka>
中,其中 Ksiazka
是我的类(基本上是一本书的属性)。然后我将整个 ArrayList 对象保存到文件 baza.bin。我通过循环遍历类 Ksiazka
的整个对象列表来做到这一点,将每个字符串一个一个地保存到文件 baza.bin 中,使用方法 writeUTF(oneOfStrings)
。当我尝试阅读文件 baza.bin 时,我看到的是问号而不是特殊字符(ą、ć、ę、ł、ń、ó、ś、ź)。我认为文件和输入数据的编码差异存在问题,但老实说我不知道如何解决。
这些是我的类 Ksiazka
的属性:
private String id;
private String tytul;
private String autor;
private String rok;
private String wydawnictwo;
private String gatunek;
private String opis;
private String ktoWypozyczyl;
private String kiedyWypozyczona;
private String kiedyDoOddania;
static String podajDana(String[] tab,int copokazac){
System.out.print(tab[copokazac]);
boolean podawajDalej = true;
String linia = "";
Scanner klawiatura = new Scanner(system.in,"utf-8");
do{
try {
podawajDalej = false;
linia = klawiatura.nextLine();
}
catch(NoSuchElementException e){
System.err.println("Wystąpił błąd w czasie podawania wartości!"
+ " Spróbuj jeszcze raz!");
}
catch(IllegalStateException e){
System.err.println("Wewnętrzny błąd programu typu 2! Zgłoś to jak najszybciej"
+ " razem z tą wiadomością");
}
}while(podawajDalej);
return linia;
}
String[] tab
只是我希望能够在屏幕上显示的字符串数组,每个集合(数组)都有自己的功能,int copokazac
是我想要显示的数组中的行数.
这个将所有数据从 ArrayList<Ksiazka>
保存到文件 baza.bin:
static void zapiszZmiany(ArrayList<Ksiazka> bazaKsiazek){
try{
RandomAccessFile plik = new RandomAccessFile("baza.bin","rw");
for(int i = 0; i < bazaKsiazek.size(); i++){
plik.writeUTF(bazaKsiazek.get(i).zwrocId());
plik.writeUTF(bazaKsiazek.get(i).zwrocTytul());
plik.writeUTF(bazaKsiazek.get(i).zwrocAutor());
plik.writeUTF(bazaKsiazek.get(i).zwrocRok());
plik.writeUTF(bazaKsiazek.get(i).zwrocWydawnictwo());
plik.writeUTF(bazaKsiazek.get(i).zwrocgatunek());
plik.writeUTF(bazaKsiazek.get(i).zwrocopis());
plik.writeUTF(bazaKsiazek.get(i).zwrocKtoWypozyczyl());
plik.writeUTF(bazaKsiazek.get(i).zwrocKiedyWypozyczona());
plik.writeUTF(bazaKsiazek.get(i).zwrocKiedyDoOddania());
}
plik.close();
}
catch (FileNotFoundException ex){
System.err.println("Nie znaleziono pliku z bazą książek!");
}
catch (IOException ex){
System.err.println("Błąd zapisu bądź odczytu pliku!");
}
}
我认为这两种方法之一存在问题(要么我在阅读时做错了什么,要么在使用 writeUTF()
将数据保存到文件时出错),但即使如此,我也尝试了一些解决它,他们都没有工作。
与讲师快速交谈后,我得到了最多可以使用 JDK 8 的信息。
解决方法
您使用了不同的阅读和写作技巧,而且它们不兼容。
尽管名称如此,但 RandomAccessFile 的 writeUTF
方法不写入 UTF-8 字符串。来自the documentation:
以与机器无关的方式使用 modified UTF-8 编码将字符串写入文件。
首先,从当前文件指针开始,将两个字节写入文件,就像通过 writeShort
方法给出要跟随的字节数一样。该值是实际写出的字节数,而不是字符串的长度。按照长度依次输出字符串的每个字符,对每个字符使用修改后的 UTF-8 编码。
writeUTF 会写一个两字节的长度,然后把字符串写成 UTF-8,除了 '\u0000'
字符写成两个 UTF-8 字节,补充字符写成两个 UTF-8 编码的代理,而不是单个 UTF-8 代码点序列。
另一方面,您正在尝试使用 new Scanner(System.in,"utf-8")
和 klawiatura.nextLine();
读取该数据。这种方法不兼容,因为:
- 文本不是真正的 UTF-8 序列。
- 在写入文本之前,写入了表示其数字长度的两个字节。它们不是可读的文本。
-
writeUTF
不写换行符。事实上,它根本不写任何终止序列。
最好的解决方案是删除所有 RandomAccessFile 的用法并用 Writer 替换它:
Writer plik = new FileWriter(new File("baza.bin"),StandardCharsets.UTF_8);
for (int i = 0; i < bazaKsiazek.size(); i++) {
plik.write(bazaKsiazek.get(i).zwrocId());
plik.write('\n');
plik.write(bazaKsiazek.get(i).zwrocTytul());
plik.write('\n');
// ...