Có cách nào dễ dàng để tránh đối phó với các vấn đề về mã hóa văn bản không?
Có cách nào dễ dàng để tránh đối phó với các vấn đề về mã hóa văn bản không?
Câu trả lời:
Bạn thực sự không thể tránh đối phó với các vấn đề mã hóa văn bản, nhưng có các giải pháp hiện có trong Apache Commons:
Reader
đến InputStream
:ReaderInputStream
Writer
đến OutputStream
:WriterOutputStream
Bạn chỉ cần chọn bảng mã mà bạn chọn.
Nếu bạn đang bắt đầu với một Chuỗi, bạn cũng có thể làm như sau:
new ByteArrayInputStream(inputString.getBytes("UTF-8"))
ReaderInputStream
triển khai tốt sẽ yêu cầu ít bộ nhớ hơn - không cần thiết phải lưu trữ tất cả các byte trong một mảng cùng một lúc.
Vâng, một Trình đọc xử lý các ký tự và một InputStream xử lý các byte. Mã hóa chỉ định cách bạn muốn biểu diễn các ký tự của mình dưới dạng byte, vì vậy bạn thực sự không thể bỏ qua vấn đề này. Để 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 bó với nó.
Về cách thực sự làm điều đó, như đã được chỉ ra, " tên rõ ràng cho các lớp này là ReaderInputStream và WriterOutputStream . " Đáng ngạc nhiên là " chúng không được bao gồm trong thư viện Java " mặc dù các lớp 'đối lập', InputStreamReader và OutputStreamWriter là bao gồm.
Vì vậy, rất nhiều người đã nghĩ ra cách triển khai của riêng họ, bao gồm cả Apache Commons IO . Tùy thuộc vào các vấn đề cấp phép, bạn có thể sẽ có thể đưa thư viện commons-io vào dự án của mình hoặc thậm chí sao chép một phần của mã nguồn (có thể tải xuống tại đây ).
Như bạn có thể thấy, tài liệu của cả hai lớp đều nói rằng "tất cả các bảng mã bộ ký tự được hỗ trợ bởi JRE đều được xử lý chính xác".
NB Một bình luận về một trong những câu trả lời khác ở đây đề cập đến lỗi này . Nhưng điều đó ảnh hưởng đến lớp Apache Ant ReaderInputStream ( ở đây ), không phải lớp Apache Commons IO ReaderInputStream.
Cũng lưu ý rằng, nếu bạn đang bắt đầu với Chuỗi, bạn có thể bỏ qua việc tạo StringReader và tạo InputStream trong một bước bằng cách sử dụng org.apache.commons.io.IOUtils từ Commons IO như sau:
InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");
Tất nhiên bạn vẫn cần phải suy nghĩ về mã hóa văn bản, nhưng ít nhất quá trình chuyển đổi đang diễn ra trong một bước.
new ByteArrayInputStream(report.toString().getBytes("utf-8"))
, phương pháp này 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ớn, nó là xấu. Hãy xem câu trả lời của tôi.
Sử dụng:
new CharSequenceInputStream(html, StandardCharsets.UTF_8);
Cách này không yêu cầu chuyển đổi trả trước đến String
và sau đó byte[]
, sẽ 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 ngay lập tức khi luồng được đọc, ngay từ StringBuffer.
Nó sử dụng CharSequenceInputStream từ dự án Apache Commons IO.
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 rằng nó sẽ giải quyết được tất cả các vấn đề về mã hóa văn bản, vốn là điều gây ác mộng.
Có một RFE, nhưng nó bị đóng, sẽ không sửa được.
Bạn không thể tránh các vấn đề về mã hóa văn bản, nhưng Apache commons-io có
Lưu ý rằng đây là các thư viện được đề cập đến trong câu trả lời của Peter trên koders.com, chỉ là các liên kết đến thư viện thay vì mã nguồn.
Bạn đang cố gắng viết nội dung của a Reader
thành an OutputStream
? Nếu vậy, bạn sẽ có thời gian dễ dàng hơn OutputStream
trong việc gói OutputStreamWriter
và viết các char
s từ Reader
đến Writer
thay vì cố gắng chuyển đổi người đọc thành 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
Cảnh báo khi sử dụng WriterOutputStream - không phải lúc nào nó cũng xử lý việc ghi dữ liệu nhị phân vào tệp một cách chính xác / giống như một luồng đầu ra thông thường. Tôi đã gặp sự cố với điều này mà tôi đã mất một thời gian để theo dõi.
Nếu bạn 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 xung quanh luồng để thực hiện. Việc chuyển đổi văn bản thành byte đáng tin cậy hơn nhiều so với cách khác, đó có thể là lý do tại sao WriterOutputStream không phải là một phần của thư viện Java tiêu chuẩn
Bạn có thể sử dụng Cactoos (không có phương thức tĩnh, chỉ có đối tượng):
Bạn cũng có thể chuyển đổi theo cách khác:
Để đọc một chuỗi trong một luồng chỉ sử dụng những gì java cung cấp.
InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));