2012-03-24 27 views
61

Tuy nhiên, tôi có mã sau đây, tôi muốn nó viết dưới dạng tệp UTF-8 để xử lý các ký tự nước ngoài. Có cách nào để làm điều này, có một số cần phải có một tham số?Viết một tệp bằng UTF-8 bằng FileWriter (Java)?

Tôi thực sự đánh giá cao sự trợ giúp của bạn về vấn đề này. Cảm ơn.

try { 
    BufferedReader reader = new BufferedReader(new FileReader("C:/Users/Jess/My Documents/actresses.list")); 
    writer = new BufferedWriter(new FileWriter("C:/Users/Jess/My Documents/actressesFormatted.csv")); 
    while((line = reader.readLine()) != null) { 
    //If the line starts with a tab then we just want to add a movie 
    //using the current actor's name. 
    if(line.length() == 0) 
     continue; 
    else if(line.charAt(0) == '\t') { 
     readMovieLine2(0, line, surname.toString(), forename.toString()); 
    } //Else we've reached a new actor 
    else { 
     readActorName(line); 
    } 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

Trả lời

42

Bạn cần sử dụng lớp OutputStreamWriter làm thông số ghi cho BufferedWriter của mình. Nó chấp nhận một mã hóa. Xem lại javadocs cho nó.

Hơi như thế này:

BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
    new FileOutputStream("jedis.txt"), "UTF-8" 
)); 

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 FileWriter 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 mà bạn đọc và viết.

EDIT

  • Bắt đầu từ API 19, bạn có thể thay thế các String "UTF-8" với StandardCharsets.UTF_8

  • Như đã đề cập trong các ý kiến ​​dưới đây của tchrist, nếu bạn có ý định để phát hiện mã hóa lỗi trong tệp của bạn, bạn sẽ bị buộc phải sử dụng cách tiếp cận OutputStreamWriter và sử dụng hàm tạo nhận bộ mã hóa ký tự.

    Hơi như

    CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); 
    encoder.onMalformedInput(CodingErrorAction.REPORT); 
    encoder.onUnmappableCharacter(CodingErrorAction.REPORT); 
    BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("jedis.txt"),encoder)); 
    

    Bạn có thể lựa chọn giữa các hành động IGNORE | REPLACE | REPORT

Ngoài ra, câu hỏi này đã được trả lời here.

+0

Đó không phải là đủ . Bạn cũng cần một 'InputStreamReader (InputStream in, CharsetDecoder dec))', chẳng hạn đối số cuối cùng là 'Charset.forName (" UTF-8 "). NewDecoder()'. – tchrist

+1

Lỗi mã hóa đầu vào sẽ tự động bị xóa nếu bạn thực hiện điều đó. – tchrist

+0

Không cần bộ mã hóa. Hàm khởi tạo chấp nhận một String, một Charset hoặc một Encoder trong cả hai lớp Input/Output. Không chắc chắn ý bạn là gì. Bạn có thể xây dựng được không? –

41

Mương FileWriterFileReader, vô dụng chính xác vì chúng không cho phép bạn chỉ định mã hóa. Thay vào đó, sử dụng

new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)

new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8);

+9

Nếu bạn không sử dụng 'Charset.forName (" UTF-8 ") rất chi tiết. NewDecoder()' argument (hoặc một số fancier construct) thay vì chỉ '" UTF-8 "', bạn sẽ không đúng được thông báo về các lỗi mã hóa (đọc: các ngoại lệ sẽ bị chặn và nó sẽ ẩn các lỗi mã hóa một cách bí ẩn). – tchrist

+2

'mới OutputStreamWriter (new FileOutputStream (tệp), StandardCharsets.UTF_8)' – Abdull

64

Safe Encoding Constructors

Bắt Java để thông báo đúng cho bạn về những lỗi mã hóa là khéo léo.Bạn phải sử dụng verbose nhất và, than ôi, các sử dụng ít nhất trong bốn contructors thay thế cho mỗi InputStreamReaderOutputStreamWriter nhận một ngoại lệ thích hợp trên một trục trặc mã hóa.

Đối với tập tin I/O, luôn luôn đảm bảo luôn luôn sử dụng như là đối số thứ hai để cả OutputStreamWriterInputStreamReader đối số encoder ưa thích:

Charset.forName("UTF-8").newEncoder() 

Có khả năng thậm chí fancier khác, nhưng không ai trong số ba đơn giản hơn khả năng làm việc cho bàn giao ngoại lệ. Những làm:

OutputStreamWriter char_output = new OutputStreamWriter(
    new FileOutputStream("some_output.utf8"), 
    Charset.forName("UTF-8").newEncoder() 
); 

InputStreamReader char_input = new InputStreamReader(
    new FileInputStream("some_input.utf8"), 
    Charset.forName("UTF-8").newDecoder() 
); 

Đối với chạy với

$ java -Dfile.encoding=utf8 SomeTrulyRemarkablyLongcLassNameGoeShere 

Vấn đề là rằng sẽ không sử dụng hình thức lập luận encoder đầy đủ cho các nhân vật suối, và do đó bạn sẽ một lần nữa bỏ lỡ vấn đề mã hóa.

dài Ví dụ

Dưới đây là một ví dụ nữa, chương trình này quản lý một quá trình thay vì một tập tin, nơi mà chúng tôi thúc đẩy hai đầu vào khác nhau byte suối và một đầu ra byte stream tất cả để tự UTF-8 suối với xử lý ngoại lệ đầy đủ:

// this runs a perl script with UTF-8 STD{IN,OUT,ERR} streams 
Process 
slave_process = Runtime.getRuntime().exec("perl -CS script args"); 

// fetch his stdin byte stream... 
OutputStream 
__bytes_into_his_stdin = slave_process.getOutputStream(); 

// and make a character stream with exceptions on encoding errors 
OutputStreamWriter 
    chars_into_his_stdin = new OutputStreamWriter(
          __bytes_into_his_stdin, 
     /* DO NOT OMIT! */ Charset.forName("UTF-8").newEncoder() 
         ); 

// fetch his stdout byte stream... 
InputStream 
__bytes_from_his_stdout = slave_process.getInputStream(); 

// and make a character stream with exceptions on encoding errors 
InputStreamReader 
    chars_from_his_stdout = new InputStreamReader(
          __bytes_from_his_stdout, 
     /* DO NOT OMIT! */ Charset.forName("UTF-8").newDecoder() 
         ); 

// fetch his stderr byte stream... 
InputStream 
__bytes_from_his_stderr = slave_process.getErrorStream(); 

// and make a character stream with exceptions on encoding errors 
InputStreamReader 
    chars_from_his_stderr = new InputStreamReader(
          __bytes_from_his_stderr, 
     /* DO NOT OMIT! */ Charset.forName("UTF-8").newDecoder() 
         ); 

Bây giờ bạn có ba nhân vật suối rằng tất cả tăng ngoại lệ về lỗi mã hóa, tương ứng gọi là chars_into_his_stdin, chars_from_his_stdoutchars_from_his_stderr.

Điều này chỉ phức tạp hơn một chút so với những gì bạn cần cho vấn đề của mình, giải pháp mà tôi đã đưa ra trong nửa đầu của câu trả lời này. Điểm mấu chốt là đây là cách duy nhất để phát hiện lỗi mã hóa.

Chỉ cần không làm cho tôi bắt đầu về trường hợp ngoại lệ ăn uống PrintStream.

+1

Câu trả lời hay, nhưng tôi nghĩ có một lỗi nhỏ với nó -'InputStreamReader char_input = new InputStreamWriter' nên đọc: 'InputStreamReader char_input = new InputStreamReader', và constructor 'InputStreamReader' nhận một' CharsetDecoder', không phải là 'CharsetEncoder'. –

+0

Nhưng đây có phải là một vấn đề thực sự, UTF-8 không thể đại diện, tôi nghĩ nó có thể mã hóa bất cứ thứ gì. –

+0

Nếu bạn muốn khiếu nại về Streams ăn ngoại lệ, hãy thử 'CipherInputStream', mà loại bỏ' của BadPaddingException', ngay cả khi họ được tạo ra bởi một dòng mật mã xác nhận :( –

4

Với văn bản tiếng Trung, tôi đã cố gắng sử dụng Charset UTF-16 và may mắn là nó hoạt động.

Hy vọng điều này có thể hữu ích!

PrintWriter out = new PrintWriter(file, "UTF-16"); 
-2

Theo tôi

Nếu bạn muốn viết theo kiểu UTF-8 Bạn sẽ vào tạo ra một byte array.Then, bạn có thể làm như sau: byte[] by=("<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"Your string".getBytes();

Sau đó, , bạn có thể viết từng byte vào tệp bạn đã tạo. Ví dụ:

OutputStream f=new FileOutputStream(xmlfile); 
    byte[] by=("<?xml version=\"1.0\" encoding=\"utf-8\"?>"+"Your string".getBytes(); 
    for (int i=0;i<by.length;i++){ 
    byte b=by[i]; 
    f.write(b); 

    } 
    f.close(); 
+0

Bạn có thể thêm một số giải thích cho mã này không? –

+0

Chào mừng bạn đến với Stack Overflow! Mặc dù đoạn mã này có thể giải quyết được câu hỏi, [bao gồm cả giải thích] (// meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho người đọc trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn. Ngoài ra, vui lòng không cố gắng gắn mã của bạn với các nhận xét giải thích, điều này làm giảm khả năng đọc của cả mã và giải thích! –

0

Kể từ Java 7 có một cách dễ dàng để xử lý mã hóa ký tự của BufferedWriter và BufferedReaders. Bạn có thể tạo một BufferedWriter trực tiếp bằng cách sử dụng lớp Files thay vì tạo các thể hiện khác nhau của Writer.Bạn có thể dễ dàng tạo ra một BufferedWriter, trong đó xem xét mã hóa ký tự, bằng cách gọi:

Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8); 

Bạn có thể tìm hiểu thêm về nó trong javadoc:

Các vấn đề liên quan