Các tài liệu API nói như sau cho readUTF8
Đọc trong một chuỗi từ tập tin này. Chuỗi đã được mã hóa bằng cách sử dụng định dạng UTF-8 được sửa đổi .
Hai byte đầu tiên được đọc, bắt đầu từ con trỏ tệp hiện tại, như thể bởi readUnsignedShort. Giá trị này cung cấp số lượng sau đây byte nằm trong chuỗi được mã hóa, không phải là độ dài của chuỗi kết quả. Các byte sau đây được hiểu là mã hóa byte ký tự theo định dạng UTF-8 đã sửa đổi và được chuyển đổi thành ký tự.
Phương pháp này chặn cho đến khi tất cả các byte được đọc, kết thúc của luồng được phát hiện hoặc ngoại lệ được ném.
Chuỗi của bạn có được định dạng theo cách này không?
Điều này dường như giải thích ngoại trừ EOF của bạn.
Tệp của bạn là tệp văn bản để sự cố thực sự của bạn là giải mã.
Câu trả lời đơn giản nhất tôi biết là:
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();
}
Hoặc bạn có thể thiết lập mã hóa hệ thống hiện tại với hệ thống sở hữu file.encoding
sang UTF-8.
java -Dfile.encoding=UTF-8 com.jediacademy.Runner arg1 arg2 ...
Bạn cũng có thể thiết lập nó như một thuộc tính hệ thống khi chạy với System.setProperty(...)
nếu bạn chỉ cần nó cho tập tin cụ thể này, nhưng trong một trường hợp như thế này, tôi nghĩ rằng tôi sẽ thích OutputStreamWriter
.
Bằng cách đặt thuộc tính hệ thống, bạn có thể sử dụng FileReader
và hy vọng rằng nó sẽ sử dụng UTF-8 làm mã hóa mặc định cho tệp của bạn. Trong trường hợp này cho tất cả các tập tin mà bạn đọc và viết.
Nếu bạn có ý định phát hiện lỗi giải mã trong tệp của mình, bạn sẽ bị buộc sử dụng phương pháp InputStreamReader
và sử dụng hàm tạo nhận bộ giải mã.
Hơi như
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));
Bạn có thể lựa chọn giữa các hành động IGNORE | REPLACE | REPORT
EDIT
Nếu bạn nhấn mạnh trong việc sử dụng RandomAccessFile
, bạn sẽ cần phải biết chính xác bù đắp của đường mà bạn đang có ý định đọc.Và không chỉ vậy, để đọc với phương thức readUTF()
, bạn nên viết tệp bằng phương thức writeUTF()
. Bởi vì phương thức này, như JavaDocs đã nói ở trên, mong đợi một định dạng cụ thể trong đó 2 byte chưa ký đầu tiên đại diện cho độ dài theo byte của chuỗi UTF-8.
Như vậy, nếu bạn làm:
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();
}
Bạn không nên có bất kỳ vấn đề đọc lại từ tập tin này bằng cách sử dụng phương pháp readUTF()
, miễn là bạn có thể xác định bù đắp của đường thẳng cho trước mà bạn muốn đọc lại.
Nếu bạn mở tệp jedis.bin
, bạn sẽ thấy đó là tệp nhị phân, không phải tệp văn bản.
Bây giờ, tôi biết rằng "Luke\n"
là 5 byte trong UTF-8 và "Obiwan\n"
là 7 byte trong UTF-8. Và phương thức writeUTF()
sẽ chèn 2 byte trước mỗi một trong các chuỗi này. Do đó, trước "Yoda\n"
có (5 + 2) + (7 + 2) = 16 byte.
Vì vậy, tôi có thể làm một cái gì đó như thế này để đạt được dòng cuối cùng:
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();
}
Nhưng điều này sẽ không hoạt động nếu bạn đã viết các tập tin với một lớp Writer
vì nhà văn không tuân theo các quy tắc định dạng của phương pháp này writeUFT()
. Trong trường hợp này, tốt nhất là tệp nhị phân của bạn sẽ được định dạng sao cho tất cả các chuỗi chiếm cùng một lượng không gian (số byte, không phải số ký tự, vì số lượng byte là biến trong UTF-8 tùy thuộc vào các ký tự trong chuỗi của bạn), nếu không phải tất cả các không gian là cần nó bạn pad nó:
Bằng cách đó bạn có thể dễ dàng tính toán bù đắp của một dòng nhất định bởi vì tất cả chúng sẽ chiếm cùng một lượng không gian.
Tôi tạo ra file văn bản này sử dụng BufferedWriter (OutputStreamWriter mới (FileOutputStream mới (..), mã hóa), nơi mã hóa là utf8 – kenny
Sau đó ou không thể sử dụng RandomAccessFile để đọc nó trở lại.Bạn phải sử dụng một lớp người đọc như BufferedReader hoặc FileReader, và đọc từ đầu cho đến khi bạn đạt đến dòng trong câu hỏi –
điều này là không hiệu quả, tôi sử dụng tìm kiếm để phân trang phôi. tôi đọc lại toàn bộ tập tin mỗi lần – kenny