2008-09-15 29 views

Trả lời

34

Bạn có thể không thực sự tránh đối phó với các vấn đề mã hóa văn bản, nhưng có những giải pháp hiện có:

Bạn chỉ cần phải chọn mã hóa của sự lựa chọn của bạn.

+6

FYI: mã ReaderInputStream có lỗi trong cách đọc byte (nó sẽ không hoạt động đối với tất cả các mã hóa). Bằng chứng: http://illegalargumentexception.blogspot.com/2009/05/java-rough-guide-to-character-encoding.html#javaencoding_stringclass Có một lỗi mở: https://issues.apache.org/bugzilla/show_bug .cgi? id = 40455 – McDowell

+0

Ngoài ra mã có bản quyền: ( – Armand

+1

Bạn có thể tìm thấy các lớp trong thư viện commons-io của Apache: http://commons.apache.org/proper/commons-io/ –

5

Tên rõ ràng cho các lớp này là ReaderInputStream và WriterOutputStream. Thật không may, chúng không được bao gồm trong thư viện Java. Tuy nhiên, google là bạn của bạn.

Tôi không chắc chắn rằng nó sẽ khắc phục tất cả các sự cố mã hóa văn bản, điều này rất đáng sợ.

There is an RFE, nhưng đã đóng, sẽ không khắc phục.

+1

https://bugs.openjdk.java.net/browse/JDK-4103785 chứa bình luận "chúng tôi có một API công cộng cho nhân vật thiết lập mã hóa ... không có lý do thuyết phục để thêm những lớp học "- vậy làm thế nào người ta làm điều này trong Java 7, mà không có thư viện bổ sung, mười hai năm xuống đường? –

4

Bạn đang cố viết nội dung của số Reader vào một số OutputStream? Nếu vậy, bạn sẽ có một thời gian dễ dàng hơn gói các OutputStream trong một OutputStreamWriter và viết char s từ Reader đến Writer, thay vì cố gắng để chuyển đổi người đọc một InputStream:

final Writer writer = new BufferedWriter(new OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8")); 
int charsRead; 
char[] cbuf = new char[1024]; 
while ((charsRead = data.read(cbuf)) != -1) { 
    writer.write(cbuf, 0, charsRead); 
} 
writer.flush(); 
// don't forget to close the writer in a finally {} block 
16

Cũng lưu ý rằng, nếu bạn đang bắt đầu với một string, bạn có thể bỏ qua việc tạo ra một StringReader và tạo ra một InputStream trong một bước sử dụng org.apache.commons.io.IOUtils từ Commons IO như vậy:

InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8"); 

Tất nhiên bạn vẫn cần suy nghĩ về mã hóa văn bản, nhưng tại st chuyển đổi đang diễn ra trong một bước.

+2

Phương pháp này về cơ bản là 'mới ByteArrayInputStream (report.toString(). GetBytes ("utf-8")) ', trong đó bao gồm việc phân bổ hai bản sao bổ sung của báo cáo trong bộ nhớ.Nếu báo cáo là lớn, nó là xấu Xem câu trả lời của tôi – Oliv

87

Nếu bạn đang bắt đầu với một String bạn cũng có thể làm như sau:

new ByteArrayInputStream(inputString.getBytes("UTF-8")) 
+2

Điều này giải quyết một vấn đề với chuỗi, nhưng không phải là bản gốc – sbeliakov

+6

Việc triển khai 'ReaderInputStream' tốt sẽ yêu cầu ít bộ nhớ hơn - không cần phải lưu trữ tất cả các byte trong một mảng cùng một lúc. –

+3

Tôi thích giải pháp này cho nó hoạt động khi bạn cần đơn vị mã kiểm tra chấp nhận đầu vào (ví dụ) đầu vào tiêu chuẩn. –

5

Bạn không thể tránh các vấn đề mã hóa văn bản, nhưng Apache commons-io

Lưu ý đây là những thư viện được nhắc đến trong câu trả lời của koders.com của Peter, chỉ liên kết đến thư viện thay vì mã nguồn.

35

Vâng, Reader có giao dịch với các ký tự và giao dịch InputStream với byte. Bảng mã chỉ định cách bạn muốn đại diện cho các ký tự của bạn dưới dạng byte, vì vậy bạn không thể bỏ qua vấn đề. Để tránh các vấn đề, ý kiến ​​của tôi là: chọn một bộ ký tự (ví dụ: "UTF-8") và gắn với nó.

Về làm thế nào để thực sự làm điều đó, như đã được chỉ ra, "tên rõ ràng cho các lớp này là ReaderInputStreamWriterOutputStream." Đáng ngạc nhiên, "những không có trong thư viện Java" mặc dù các lớp 'đối diện', InputStreamReaderOutputStreamWriterđược bao gồm.

Vì vậy, nhiều người đã đưa ra các triển khai của riêng họ, bao gồm ApacheCommons IO. Tùy thuộc vào các vấn đề cấp phép, bạn có thể sẽ bao gồm thư viện commons-io trong dự án của bạn, hoặc thậm chí sao chép một phần mã nguồn (có thể tải xuống here).

Như bạn có thể thấy, tài liệu hướng dẫn cả lớp khẳng định rằng "tất cả các mã hóa charset được hỗ trợ bởi JRE được xử lý một cách chính xác" .

N.B. Nhận xét về một trong các câu trả lời khác ở đây đề cập đến this bug. Nhưng điều đó ảnh hưởng đến lớp học Apache Ant ReaderInputStream (here), không Apache Commons IO lớp ReaderInputStream.

1

Cảnh báo khi sử dụng WriterOutputStream - nó không phải lúc nào cũng xử lý ghi dữ liệu nhị phân vào một tệp đúng/giống như luồng đầu ra thông thường. Tôi đã có một vấn đề với điều này mà đã cho tôi một thời gian để theo dõi.

Nếu có thể, tôi khuyên bạn nên sử dụng luồng đầu ra làm cơ sở của mình và nếu bạn cần viết chuỗi, hãy sử dụng trình bao bọc OUtputStreamWriter quanh luồng để thực hiện. Nó là xa đáng tin cậy hơn để chuyển đổi văn bản để byte so với cách khác xung quanh, đó là khả năng lý do tại sao WriterOutputStream không phải là một phần của thư viện chuẩn của Java

7

Sử dụng:

new CharSequenceInputStream(html, StandardCharsets.UTF_8); 

Bằng cách này không yêu cầu trả trước chuyển đổi thành String và sau đó đến byte[], phân bổ nhiều bộ nhớ heap hơn, trong trường hợp báo cáo lớn. Nó chuyển đổi thành byte khi di chuyển khi luồng được đọc, ngay từ StringBuffer.

Nó sử dụng CharSequenceInputStream từ dự án Apache Commons IO.

-1

Để đọc chuỗi trong luồng chỉ bằng cách sử dụng nguồn cung cấp java.

InputStream s = new BufferedInputStream(new ReaderInputStream(new StringReader("a string"))); 
+5

ReaderInputStream nằm trong Apache Commons IO. –

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