2009-08-26 20 views
6

Tôi có một ứng dụng Java nhận dữ liệu qua ổ cắm bằng cách sử dụng InputStreamReader. Nó báo cáo "Cp1252" từ phương pháp getEncoding của nó:Làm thế nào để bạn chỉ định một giá trị Java file.encoding phù hợp với trang mã Windows cơ bản?

/* java.net. */ Socket Sock = ...; 
InputStreamReader is = new InputStreamReader(Sock.getInputStream()); 
System.out.println("Character encoding = " + is.getEncoding()); 
// Prints "Character encoding = Cp1252" 

Điều đó không nhất thiết phải phù hợp với những gì các báo cáo hệ thống như trang mã của nó. Ví dụ:

 
C:\>chcp 
Active code page: 850 

Ứng dụng có thể nhận byte 0x81, trong trang mã 850 đại diện cho ký tự ü. Chương trình giải thích rằng byte với mã trang 1252, không xác định bất kỳ ký tự nào ở giá trị đó, vì vậy tôi nhận được một dấu chấm hỏi thay thế.

tôi đã có thể làm việc xung quanh vấn đề này cho một khách hàng sử dụng mã trang 850 bằng cách thêm một tùy chọn dòng lệnh trong tập tin batch để khởi động ứng dụng:

 
java.exe -Dfile.encoding=Cp850 ... 

Nhưng không phải tất cả khách hàng của tôi sử dụng mã trang 850, tất nhiên. Làm thế nào tôi có thể sử dụng Java để sử dụng một trang mã tương thích với hệ thống Windows cơ bản? Sở thích của tôi sẽ là một cái gì đó tôi chỉ có thể đưa vào tập tin thực thi, để lại mã Java hoang sơ:

 
ENC=... 
java.exe -Dfile.encoding=%ENC% ... 

Trả lời

5

Liên quan đến các snippit mã, câu trả lời đúng là sử dụng appropriate constructor cho InputStreamReader mà không chuyển đổi mã đúng . Bằng cách đó, việc mã hóa mặc định trên hệ thống là gì, bạn biết bạn đang nhận được mã hóa chính xác tương ứng với những gì bạn đang nhận được trên socket. Sau đó, bạn có thể chỉ định mã hóa khi bạn viết ra tệp nếu cần, thay vì dựa vào mã hóa hệ thống, nhưng tất nhiên khi họ mở tệp trên hệ thống đó, chúng có thể gặp sự cố, nhưng hệ thống cửa sổ hiện đại hỗ trợ UTF- 8, vì vậy bạn có thể viết ra các tập tin trong UTF-8 nếu bạn cần (nội bộ Java là đại diện cho tất cả các chuỗi như unicode 16 bit).

Tôi nghĩ đây là giải pháp "đúng" nói chung sẽ tương thích nhất với phạm vi lớn nhất của các hệ thống cơ bản.

+0

+1. BTW Trên hệ thống Windows 7 của tôi, trang mã hoạt động là 850, nhưng Java báo cáo "Cp1252" là thuộc tính hệ thống "file.encoding". –

+1

Các máy khách và máy chủ sẽ được cấu hình với cùng một mã hóa, bất kỳ điều gì có thể cho bất kỳ khách hàng nào. Một ứng dụng không phải Java gửi dữ liệu ký tự đến máy chủ bằng cách sử dụng trang mã cục bộ, máy chủ lưu trữ dữ liệu và sau đó máy chủ gửi nó đến ứng dụng Java. Không ai lưu trữ trang mã là gì, bởi vì miễn là mọi người đều sử dụng cùng một trang, điều đó không quan trọng. Vấn đề là ứng dụng Java không hợp tác; nó luôn sử dụng Cp1252. (Giải pháp "đúng" là thay đổi giao thức để buộc mọi thứ, ví dụ như UTF-8, nhưng thay đổi giao thức sẽ phá vỡ mọi cài đặt hiện có.) –

+0

Sau đó, có vẻ như G_A có câu trả lời của bạn. Một tùy chọn khác là để có báo cáo ứng dụng không java cho ứng dụng java của bạn những gì nó nghĩ rằng mã hóa là, và sau đó sử dụng các nhà xây dựng thích hợp, như đã nêu ở trên. – Yishai

4

Windows có thêm biến chứng khi có hai mã hoạt động. Trong ví dụ của bạn cả hai 1252 và 850 là chính xác, nhưng chúng phụ thuộc vào cách chương trình đang được chạy. Đối với các ứng dụng GUI, Windows sẽ sử dụng trang mã ANSI, cho các ngôn ngữ Tây Âu thông thường sẽ là 1252. Tuy nhiên, dòng lệnh sẽ báo cáo mã mã OEM là 850 cho cùng một ngôn ngữ.

+0

Bạn đã thực hiện các tuyên bố đúng, nhưng tôi không chắc họ trả lời câu hỏi của tôi như thế nào. Rõ ràng, trang mã OEM là trang mã Java cần phải tương thích. Vì vậy, làm thế nào để tôi chọn một giá trị 'file.encoding' dựa trên đó? Cách chương trình đang chạy là thông qua 'java.exe'. –

4

Nếu giá trị trang mã mà trở lại từ một lệnh chcp sẽ trả về giá trị mà bạn cần, bạn có thể sử dụng lệnh sau đây để có được những trang mã

C:\>for /F "Tokens=4" %I in ('chcp') Do Set CodePage=%I 

này đặt biến bảng mã để mã giá trị trang trở về từ chcp

C:\>echo %CodePage% 
437 

bạn có thể sử dụng giá trị này trong file bat của bạn bằng cách đặt trước từ đó Cp

C:\>echo Cp%CodePage% 
Cp437 

Nếu khi bạn đặt này thành một file bat,% I giá trị trong lệnh đầu tiên sẽ cần phải được thay thế bằng %% Tôi

+0

Điều này có vẻ đầy hứa hẹn, nhưng nó dựa trên các giả định nhất định về định dạng của đầu ra 'chcp', có thể khác với các hệ thống không phải tiếng Anh. Ví dụ, trong tiếng Đức, trang mã nằm trong mã thông báo 3 và có một khoảng thời gian sau số: "Aktive Codepage: 850." –

+0

Đây là cách nó hoạt động ngay cả đối với một hệ thống của Đức: 'FOR/F" TOKENS = 2 DELIMS = :."%% I IN ('chcp') DO SET cp = %% I', sau đó cắt không gian với' set cp =% cp: =% 'và cuối cùng' echo Cp% cp% ' – fubar

+0

Xem giải pháp này tại đây: [Nhận windows cmd codepage với tập tin batch hoặc lệnh đơn] (http://stackoverflow.com/a/26675217/2773737) – fubar

6

Mã hóa mặc định được sử dụng bởi cmd.exeCp850 (hoặc bất cứ điều gì "OEM" CP có nguồn gốc cho hệ điều hành); mã hóa hệ thống là Cp1252 (hoặc bất kỳ "ANSI" CP nào có nguồn gốc từ hệ điều hành). Gory details here. Một cách để khám phá mã hóa bảng điều khiển sẽ là làm điều đó via native code (xem GetConsoleOutputCP cho mã hóa bảng điều khiển hiện tại; xem GetACP cho mã hóa "ANSI" mặc định; etc.).

Thay đổi mã hóa qua chuyển đổi -D sẽ ảnh hưởng đến tất cả các cơ chế mã hóa mặc định của bạn, bao gồm cả chuyển hướng stdout/stdin/stderr. Nó không phải là một giải pháp lý tưởng.

Tôi đã đưa ra tập lệnh WSH này có thể đặt bảng điều khiển cho hệ thống ANSI mã, nhưng chưa tìm ra cách chuyển đổi sang phông chữ TrueType theo chương trình.

'file: setacp.vbs 
'usage: cscript /Nologo setacp.vbs 
Set objShell = CreateObject("WScript.Shell") 
'replace ACP (ANSI) with OEMCP for default console CP 
cp = objShell.RegRead("HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001" &_ 
           "\Control\Nls\CodePage\ACP") 
WScript.Echo "Switching console code page to " & cp 
objShell.Exec "chcp.com " & cp 

(Đây là kịch bản WSH đầu tiên của tôi, vì vậy nó có thể có những thiếu sót - Tôi không quen thuộc với các điều khoản đăng ký đọc.)

Sử dụng một phông chữ TrueType là một yêu cầu cho việc sử dụng ANSI/Unicode với cmd.exe . Tôi sẽ xem xét một chuyển đổi có lập trình thành phông chữ tốt hơn khi thời gian cho phép.

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