首页 > 解决方案 > RandomAccessFile 方法将用户输入保存到文件的问题

问题描述

我对用户的输入有疑问。我需要将用户的输入保存到二进制文件中,当我读取它并在屏幕上显示它时,它无法正常工作。我不想放几百行,所以我会尝试以更紧凑的形式来描述它。项目属性中 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 的信息。

标签: javajava.util.scannerrandomaccessfile

解决方案


您正在使用不同的技术进行阅读和写作,并且它们不兼容。

尽管有名字,但writeUTFRandomAccessFile 的方法不会写入 UTF-8 字符串。从文档中

以与机器无关的方式使用修改后的 UTF-8编码将字符串写入文件。

首先,将两个字节写入文件,从当前文件指针开始,就像通过writeShort给出后面字节数的方法一样。这个值是实际写出的字节数,而不是字符串的长度。在长度之后,按顺序输出字符串的每个字符,对每个字符使用修改后的 UTF-8 编码。

writeUTF 将写入一个两个字节的长度,然后将字符串写入为 UTF-8,除了'\u0000'字符写入为两个 UTF-8 字节并且补充字符写入为两个 UTF-8 编码的代理项,而不是单个 UTF-8 代码点序列.

另一方面,您正在尝试使用new Scanner(System.in, "utf-8")and读取该数据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');
    // ...

推荐阅读