2011-02-07 32 views
8

Đây là bài đăng đầu tiên của tôi để ngăn xếp tràn. Tôi đã làm Java từ năm 1998, vì vậy tôi không phải là người mới bắt đầu. Gần đây tôi gặp phải một vấn đề mã hóa ký tự tệp mà tôi không thể nhớ bao giờ gặp phải. Nó khá phổ biến để phải nhận thức được mã hóa ký tự của các tập tin văn bản và viết mã xử lý mã hóa chính xác khi chạy trên các nền tảng khác nhau. Nhưng vấn đề tôi tìm thấy là do biên soạn trên một nền tảng khác từ nền tảng thực thi. Điều đó hoàn toàn bất ngờ, bởi vì trong kinh nghiệm của tôi khi javac tạo ra một tệp lớp, các tham số quan trọng là nguồn java và các tham số đích, và phiên bản của JDK thực hiện biên dịch. Trường hợp của tôi, các lớp được biên dịch với JDK 1.6.0_22 trên Mac OS X hoạt động khác với các lớp được biên dịch với 1.6.0_23-b05 trên Linux, khi chạy trên Mac OS X. Nguồn và đích được chỉ định là 1.4.Vấn đề mã hóa tệp nền tảng trình biên dịch Java

Một chuỗi được mã hóa dưới dạng ISO-8859_1 trong bộ nhớ đã được ghi vào đĩa bằng phương thức println PrintStream. Tùy thuộc vào nền tảng mà mã Java được biên dịch trên, chuỗi được viết khác nhau. Điều này dẫn đến một lỗi. Việc sửa lỗi là để chỉ định tệp mã hóa một cách rõ ràng khi viết và đọc tệp.

Điều làm tôi ngạc nhiên là hành vi này khác nhau tùy thuộc vào nơi các lớp được biên soạn, không phải trên nền tảng lớp học được chạy. Tôi khá quen thuộc với mã Java hoạt động khác nhau khi chạy trên các nền tảng khác nhau. Nhưng có một chút đáng sợ khi mã giống nhau, được biên dịch trên các nền tảng khác nhau, chạy khác nhau trên cùng một nền tảng.

Có ai gặp sự cố cụ thể này không? Dường như nó có thể bị bệnh cho bất kỳ mã Java nào đọc và ghi các chuỗi để gửi mà không chỉ định rõ ràng mã hóa ký tự. Và mức độ thường xuyên được thực hiện?

Cảm ơn,

Richard Brewster http://rabbitsoftware.com

+0

là tệp có vấn đề được mã hóa là utf-8? Có các ký tự có vấn đề trong nguồn hay các ký tự chỉ không hợp lệ ** sau ** biên dịch chỉ trên máy cụ thể đó? –

+0

Được biên dịch vào các lớp học bằng cách sử dụng cuối cùng tĩnh (biên dịch chung kết tĩnh "bakes" các chuỗi vào lớp)? hoặc khi bạn nói ghi vào đĩa là bạn serializing dữ liệu? tuần tự hóa một cá thể lớp? Phương pháp tuần tự hóa được biên dịch với mã hóa mặc định (ví dụ: biên dịch nền tảng)? –

+0

@Steve B .: Trên thực tế, tất cả các chuỗi ký tự và các chuỗi hằng số biên dịch khác được "baken" vào lớp, không chỉ các chuỗi cuối cùng. –

Trả lời

4

tôi đánh bạo đoán rằng có một vấn đề chuyển mã trong giai đoạn xây dựng và trình biên dịch thiếu định hướng như bảng mã của một tập tin nguồn (ví dụ thấy javac -encoding chuyển đổi).

Trình biên dịch thường sử dụng mã hóa mặc định của hệ thống nếu bạn không cụ thể có thể dẫn đến chuỗi và char literals bị hỏng (bên trong, bytecode Java sử dụng biểu mẫu UTF-8 đã sửa đổi, vì vậy tệp nhị phân có thể di chuyển). Đây là cách duy nhất tôi có thể tưởng tượng rằng các vấn đề đang được giới thiệu tại thời gian biên dịch.

Tôi đã viết một chút về điều này here.

7

Không có những thứ như vậy một Chuỗi được mã hóa dưới dạng ISO-8859-1 trong bộ nhớ. Các chuỗi Java trong bộ nhớ luôn là chuỗi Unicode. (Được mã hóa bằng UTF-16, nhưng bạn không thực sự cần đến bây giờ).

Mã hóa chỉ xuất hiện khi bạn nhập hoặc xuất chuỗi - sau đó, không được mã hóa rõ ràng, nó sử dụng mặc định hệ thống (mà trên một số hệ thống phụ thuộc vào cài đặt người dùng).

Như đã nói bởi McDowell, mã hóa thực sự của tệp nguồn của bạn phải khớp với mã hóa mà trình biên dịch của bạn giả định về tệp nguồn của bạn, nếu không bạn sẽ gặp sự cố khi bạn quan sát.Bạn có thể đạt được điều này bằng một vài cách:

  • Tùy chọn trình biên dịch, mã hóa tệp nguồn của bạn. (Với kiến, bạn đặt tham số encoding=.)
  • Sử dụng trình chỉnh sửa của bạn hoặc bất kỳ công cụ nào khác (như recode) để thay đổi mã hóa tệp của bạn thành mặc định của trình biên dịch.
  • sử dụng native2ascii (với tùy chọn -encoding phù hợp) để dịch tệp nguồn của bạn thành ASCII với \uXXXX -các hình ảnh.

Trong trường hợp cuối cùng, sau này bạn có thể biên dịch tệp này ở mọi nơi với mọi mã hóa mặc định, vì vậy, đây có thể là cách để đi nếu bạn mã hóa những người không biết mã hóa ở đâu đó.

Nếu bạn có một dự án lớn hơn bao gồm nhiều hơn một tệp, tất cả chúng nên có cùng một mã hóa, vì trình biên dịch chỉ có một chuyển đổi như vậy, chứ không phải một số.

Trong tất cả các dự án tôi đã có trong những năm qua, tôi luôn mã hóa tất cả các tệp của mình trong UTF-8 và trong tệp xây dựng kiến ​​của tôi đặt tham số encoding="utf-8" cho tác vụ javac. (Trình soạn thảo của tôi đủ thông minh để tự động nhận dạng mã hóa, nhưng tôi đặt mặc định thành UTF-8.)

Mã hóa quan trọng đối với các công cụ xử lý mã nguồn khác, như javadoc. (Ở đó bạn nên bổ sung các -charset-docencoding tùy chọn cho đầu ra -. Họ phải phù hợp, nhưng có thể khác nhau đối với source -encoding)

+0

Điều này không phải làm với mã hóa nguồn. Không có chuỗi ký tự nào có liên quan. Một chuỗi được đọc từ một kết nối mạng và sau đó ghi vào một tập tin. Những gì tôi có nghĩa là bởi 'được mã hóa trong bộ nhớ như ISO-8859-1' là luồng đầu vào được đọc bằng cách sử dụng bộ ký tự đó, bởi vì đó là cách nó được mã hóa. –

+0

"không có mã hóa rõ ràng, nó sử dụng hệ thống mặc định" Có, nhưng mặc định hệ thống của máy ảo thời gian chạy, phải không? Trong trường hợp này, mã hóa dường như được xác định bởi nền tảng biên dịch. Một PrintStream hoạt động khác nhau, tùy thuộc vào nền tảng biên dịch. Đây không phải là hành vi di động. Bạn có thấy quan điểm của tôi chưa? –

+0

Tôi nghĩ rằng chúng ta cần một ví dụ tối thiểu cho mã của bạn. Điều này trông giống như hai trình biên dịch trên hai hệ thống được lựa chọn phương pháp khác nhau. –

1

Tôi đã có vấn đề tương tự khi sử dụng tên biến mà không phải là ascii (Σ , σ, Δ, v.v.) khi thực hiện công thức toán học. Trên Linux, nó sử dụng mã hóa UTF-8 trong khi diễn giải. Trên các cửa sổ, nó phàn nàn về các tên không hợp lệ vì các cửa sổ sử dụng ISO-LATIN-1. Giải pháp là để xác định mã hóa trong kịch bản kiến ​​tôi đã sử dụng để biên dịch các tệp này.

+0

Tốt, tôi nghĩ mọi người thường viết 'Sigma' (hoặc' sum'), 'sigma',' delta' và cứ thế thay vì sử dụng đúng chữ cái Hy Lạp. Tôi đã từng tạo một biến có tên 'ℕ'. Tôi muốn gọi nó là 'ℕ₀', nhưng javac không chấp nhận điều này, vì' ₀' không phải là chữ số cho Java. –

+0

@ Paŭlo Ebermann Vấn đề tôi có là có quá nhiều biến và các phương trình phức tạp đủ để tài liệu là một PITA. Tôi đã sử dụng các ký tự đặc biệt và tài liệu/bằng chứng về tính chính xác là "Xem: skolnik, pp XXX-XXX". Thực tế là biến này giống với văn bản khiến người khác dễ hiểu hơn nhiều. – KitsuneYMG

0

Luôn sử dụng mã thoát (ví dụ: \uxxxx) trong tệp nguồn của bạn và điều này sẽ không có vấn đề gì. @ Paulo đã đề cập đến điều này, nhưng tôi muốn gọi nó một cách rõ ràng.

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