使用RandomAccessFile保存用户输入至二进制文件时特殊字符显示异常求助
解决波兰语特殊字符写入二进制文件后显示问号的问题
结合你提供的代码和JDK8的限制,我判断问题主要出在用户输入的编码处理环节——RandomAccessFile的writeUTF()和readUTF()是配对的Modified UTF-8实现,本身不会导致波兰语特殊字符(ą, ć, ę等)乱码,核心问题是输入读取时的编码与控制台实际编码不匹配,导致字符串在存入内存时就已经损坏了。
下面是具体的修复方案:
1. 修复输入读取的编码适配问题
Windows CMD(包括NetBeans内置控制台在Windows下的环境)默认使用的是CP1250编码(波兰语专属编码),而你的代码强制指定Scanner用UTF-8读取,这就导致输入的特殊字符被错误解码,最终存储的是损坏的字符,写入文件后自然显示为问号。
方案一:动态适配控制台编码
修改podajDana方法中的Scanner初始化逻辑,自动识别系统并使用对应编码:
static String podajDana(String[] tab, int coPokazac){ System.out.print(tab[coPokazac]); boolean podawajDalej = true; String linia = ""; // 动态获取控制台编码:Windows用CP1250,其他系统用默认UTF-8 String encoding = System.getProperty("file.encoding"); if (System.getProperty("os.name").toLowerCase().contains("win")) { encoding = "CP1250"; } Scanner klawiatura = new Scanner(System.in, encoding); 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; }
方案二:使用System.console()替代Scanner(更可靠)
System.console()会自动适配控制台的编码,避免手动指定编码的麻烦,同时处理输入的兼容性更好:
static String podajDana(String[] tab, int coPokazac){ System.out.print(tab[coPokazac]); boolean podawajDalej = true; String linia = ""; Console console = System.console(); if (console != null) { // 使用Console读取,自动适配编码 do{ try { podawajDalej = false; linia = console.readLine(); } catch(IOException e){ System.err.println("Wystąpił błąd w czasie podawania wartości!" + " Spróbuj jeszcze raz!"); } }while(podawajDalej); } else { // 回退到Scanner,适配Windows编码 String encoding = System.getProperty("file.encoding"); if (System.getProperty("os.name").toLowerCase().contains("win")) { encoding = "CP1250"; } Scanner klawiatura = new Scanner(System.in, encoding); 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; }
2. 确认读取文件的方法正确
确保你读取baza.bin时,使用的是RandomAccessFile.readUTF()方法——因为writeUTF()写入的是Modified UTF-8格式,必须用对应的readUTF()才能正确解码,示例读取逻辑如下:
static ArrayList<Ksiazka> wczytajBaze(){ ArrayList<Ksiazka> baza = new ArrayList<>(); try{ RandomAccessFile plik = new RandomAccessFile("baza.bin","r"); while (plik.getFilePointer() < plik.length()) { Ksiazka ksiazka = new Ksiazka(); ksiazka.ustawId(plik.readUTF()); ksiazka.ustawTytul(plik.readUTF()); ksiazka.ustawAutor(plik.readUTF()); ksiazka.ustawRok(plik.readUTF()); ksiazka.ustawWydawnictwo(plik.readUTF()); ksiazka.ustawGatunek(plik.readUTF()); ksiazka.ustawOpis(plik.readUTF()); ksiazka.ustawKtoWypozyczyl(plik.readUTF()); ksiazka.ustawKiedyWypozyczona(plik.readUTF()); ksiazka.ustawKiedyDoOddania(plik.readUTF()); baza.add(ksiazka); } 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!"); } return baza; }
额外测试建议
- 如果使用NetBeans运行程序,确保NetBeans的控制台编码确实是UTF-8:打开
Tools -> Options -> Miscellaneous -> Encoding,确认设置为UTF-8。 - 如果在CMD中手动运行程序,可以先执行
chcp 65001切换到UTF-8编码,再启动程序,验证是否能正常读取特殊字符。
内容的提问来源于stack exchange,提问作者Daniel1490
相关产品推荐
相关产品推荐

