la documentazione API dicono quanto segue per readUTF8
Legge in una stringa da questo file. La stringa è stata codificata utilizzando un formato UTF-8 modificato .
I primi due byte vengono letti, a partire dal puntatore del file corrente, come se readUnsignedShort. Questo valore indica il numero dei seguenti byte nella stringa codificata, non la lunghezza della stringa risultante. I seguenti byte vengono quindi interpretati come byte che codificano i caratteri nel formato UTF-8 modificato e vengono convertiti in caratteri .
Questo metodo blocca fino a quando non vengono letti tutti i byte, viene rilevata la fine del flusso oppure viene generata un'eccezione.
La stringa è stata formattata in questo modo?
Questo sembra spiegare il tuo EOF eccetto.
Il file è un file di testo, quindi il problema reale è la decodifica.
La risposta più semplice che conosco è:
try(BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("jedis.txt"),"UTF-8"))){
String line = null;
while((line = reader.readLine()) != null){
if(line.equals("Obi-wan")){
System.out.println("Yay, I found " + line +"!");
}
}
}catch(IOException e){
e.printStackTrace();
}
oppure è possibile impostare la codifica del sistema corrente con la proprietà di sistema file.encoding
a UTF-8.
java -Dfile.encoding=UTF-8 com.jediacademy.Runner arg1 arg2 ...
Si può anche impostare come una proprietà di sistema in fase di esecuzione con System.setProperty(...)
se è necessario solo per questo file specifico, ma in un caso come questo penso io preferirei il OutputStreamWriter
.
Impostando la proprietà di sistema è possibile utilizzare FileReader
e prevedere che utilizzerà UTF-8 come codifica predefinita per i file. In questo caso per tutti i file che leggi e scrivi.
Se si desidera rilevare errori di decodifica nel file, si sarà costretti a utilizzare l'approccio InputStreamReader
e utilizzare il costruttore che riceve un decodificatore.
Un po 'come
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPORT);
decoder.onUnmappableCharacter(CodingErrorAction.REPORT);
BufeferedReader out = new BufferedReader(new InpuStreamReader(new FileInputStream("jedis.txt),decoder));
Si può scegliere tra le azioni IGNORE | REPLACE | REPORT
EDIT
Se ti ostini ad utilizzare RandomAccessFile
, si avrebbe bisogno di sapere l'esatta offset della linea che si intendono leggereE non solo, per leggere con il metodo readUTF()
, dovresti aver scritto il file con il metodo writeUTF()
. Poiché questo metodo, come JavaDocs indicato sopra, si aspetta una formattazione specifica in cui i primi 2 byte senza segno rappresentano la lunghezza in byte della stringa UTF-8.
Come tale, se si fare:
try(RandomAccessFile raf = new RandomAccessFile("jedis.bin", "rw")){
raf.writeUTF("Luke\n"); //2 bytes for length + 5 bytes
raf.writeUTF("Obiwan\n"); //2 bytes for length + 7 bytes
raf.writeUTF("Yoda\n"); //2 bytes for lenght + 5 bytes
}catch(IOException e){
e.printStackTrace();
}
non dovreste avere problemi di lettura indietro da questo file utilizzando il metodo readUTF()
, fino a quando è possibile determinare l'offset della linea di data che si desidera rileggi.
Se si apre il file jedis.bin
si noterà è un file binario, non un file di testo.
Ora, so che "Luke\n"
è 5 byte in UTF-8 e "Obiwan\n"
è 7 byte in UTF-8. E che il metodo writeUTF()
inserirà 2 byte davanti a ciascuna di queste stringhe. Pertanto, prima di "Yoda\n"
ci sono (5 + 2) + (7 + 2) = 16 byte.
Così, ho potuto fare qualcosa di simile per raggiungere l'ultima riga:
try (RandomAccessFile raf = new RandomAccessFile("jedis.bin", "r")) {
raf.seek(16);
String val = raf.readUTF();
System.out.println(val); //prints Yoda
} catch (IOException e) {
e.printStackTrace();
}
Ma questo non funzionerà se hai scritto il file con una classe Writer
perché gli scrittori non seguono le regole di formattazione del metodo writeUFT()
.
In un caso come questo, la cosa migliore sarebbe che il file binario sarebbe essere formattato in modo tale che tutte le stringhe occupavano la stessa quantità di spazio (numero di byte, non il numero di characteres, perché il numero di byte è variabile in UTF-8 a seconda dei caratteri nella stringa), se non è tutto lo spazio è necessario lo si riempie:
In questo modo è possibile calcolare facilmente l'offset di una determinata linea perché tutti occuperebbero il stessa quantità di spazio.
Ho creato questo file di testo utilizzando BufferedWriter (nuova OutputStreamWriter (nuova FileOutputStream (..), la codifica), dove la codifica è utf8 – kenny
Poi ou non possono usare RandomAccessFile per leggerlo. Devi usare una classe di lettore come BufferedReader o FileReader e leggere dall'inizio fino a raggiungere la riga nella domanda –
questo non è efficiente, io cerco di preformare il paging. per rileggere l'intero file ogni volta. – kenny