2009-01-31 9 views
6

파일에 iso-8859-1로 인코딩되어 있으며, ô 같은 문자가 포함되어 있습니다.Java 응용 프로그램 : iso-8859-1로 인코딩 된 파일을 올바르게 읽을 수 없습니다.

File in = new File("myfile.csv"); 
InputStream fr = new FileInputStream(in); 
byte[] buffer = new byte[4096]; 
while (true) { 
    int byteCount = fr.read(buffer, 0, buffer.length); 
    if (byteCount <= 0) { 
     break; 
    } 

    String s = new String(buffer, 0, byteCount,"ISO-8859-1"); 
    System.out.println(s); 
} 

그러나 오 문자는 항상 왜곡, 일반적으로 인쇄되어

나는 자바 코드, 같은이 파일을 읽고있다? .

본인은 주제를 읽었으며 (조금 배우게 됨) 예.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058

  • http://www.ingrid.org/java/i18n/utf-16/http://www.joelonsoftware.com/articles/Unicode.html
    • 하지만 여전히이 작업

      는 흥미롭게도이 내 로컬 PC (XP)하지만 내 리눅스 상자에서 작동 얻을 수 없습니다.

      내 JDK 사용 (그들은 표준, 그래서이 더 깜짝 없음) 필요한 캐릭터 세트를 지원하는지 확인했다

      : 당신이 당신의 내부에 뭐가 있는지보고 디버거에서 프로그램을 실행하려고 할 수있는 경우

      System.out.println(java.nio.charset.Charset.availableCharsets()); 
      
  • +0

    필자는 단지 파일의 내용을 고양이가 쓰면 리눅스 터미널을 사용하여 문자 나 원본 파일을 올바르게 볼 수 있다고 덧붙여 야합니다. – Joel

    +0

    터미널에서 어떤 문자 인코딩을 사용하고 있습니까? – McDowell

    +0

    흥미롭게도 - 런타임 Java 속성 "-Dfile.encoding = UTF16"을 추가하면 예상대로 작동하지만, 왜 이것이 중요한지는 알 수 없지만 해결책으로 보지는 않지만 해킹을 더 많이 보게됩니다. UTF8로 설정된 속성에서는 작동하지 않습니다. – Joel

    답변

    12

    파일이 이 아니며 실제로는이 ISO-8859-1로 인코딩 된 것으로 의심됩니다. 그렇지 않으면 System.out에서 문자를 인쇄하는 방법을 알 수 없습니다.

    첫 번째를 확인하려면 파일에서 관련 바이트를 검사하는 것이 좋습니다. 제를 확인하는 것은, 그 결과는 244 소수점되어야 두 경우

    System.out.println((int) s.getCharAt(index)); 
    

    그것을 프린트 아웃 문자열의 중요한 특성을 조사; 0xf4 16 진수.

    일반적인 조언을 위해 my article on Unicode debugging을 참조하십시오 (제시된 코드는 C#이지만 자바로 변환하기 쉽고 원칙은 동일합니다).

    일반적으로, 나는 적절한 인코딩으로 InputStreamReader으로 스트림을 래핑 할 것입니다. "손으로"새 문자열을 만드는 것보다 쉽습니다. 나는 이것이 단지 데모 코드일지도 모른다는 것을 알고 있습니다.

    편집 :

    System.out.println("Here's the character: \u00f4"); 
    
    +0

    linux 파일 도구를 사용하여 파일 형식을 테스트했습니다. 파일 --mime FranceJ2.csv FranceJ2.csv : text/plain; charset = iso-8859-1 또한 정확하게 읽을 수 있음을 확인했습니다. 예를 들어, vi 하지만 나는 당신의 제안을 따를 것입니다. – Joel

    +1

    문자 인코딩을 자동으로 검색하려고하는 도구를 신뢰하지 마십시오. 그것들은 언제나 경험적 방법에 기반을두고 있어야합니다. 그들은 당신의 파일이 정말로 포함 할 텍스트인지 알지 못합니다. –

    +0

    파일의 hexdump는 다음을 산출합니다. 0000000 0df4 000a (모든 제안 !?) – Joel

    3

    's'문자열이 만들어집니다. 올바른 내용을 가지고있을 수 있지만 System.out.println (s) 호출 후 출력이 왜곡됩니다. 이 경우 Java가 사용자의 출력 인코딩과 Linux의 터미널/콘솔 문자 인코딩 사이에서 불일치가있을 수 있습니다.

    9

    바이트의 고정 된 크기의 블록으로 파일을 구문 분석 일부 문자가있다 어떤 경우 --- 좋은되지 않은 : 여기에 콘솔이 작동할지 여부를 입증 할 수있는 정말 쉬운 방법입니다 두 개의 블록에 걸친 바이트 표현? 대신 적절한 문자 인코딩으로 InputStreamReader를 사용

    BufferedReader br = new BufferedReader(
         new InputStreamReader(
         new FileInputStream("myfile.csv"), "ISO-8859-1"); 
    
    char[] buffer = new char[4096]; // character (not byte) buffer 
    
    while (true) 
    { 
         int charCount = br.read(buffer, 0, buffer.length); 
    
         if (charCount == -1) break; // reached end-of-stream 
    
         String s = String.valueOf(buffer, 0, charCount); 
         // alternatively, we can append to a StringBuilder 
    
         System.out.println(s); 
    } 
    

    을, BTW 유니 코드 문자가 실제로 제대로 표시 할 수 있는지 확인해야합니다.프로그램 출력을 파일로 재지 정하여 원래 파일과 비교할 수도 있습니다.

    Jon Skeet과 마찬가지로 콘솔 관련 문제 일 수도 있습니다. System.console().printf(s)을 시도해 차이점이 있는지 확인하십시오.

    1

    기본적으로 로컬 XP PC에서는 작동하지만 Linux에서는 작동하지 않고 똑같은 파일을 구문 분석하면 (예 : 상자간에 이진 방식으로 파일을 전송 한 경우), 아마도이 파일은 System.out.println 호출. 어떻게 출력을 확인할 지 모르겠지만 XP 상자에서 원격 셸로 연결하면이 셸 (및 클라이언트)의 문자 집합을 고려해야합니다.

    또한 Zach Scrivena가 제안한 것은 사실입니다. 그런 식으로 데이터 청크에서 문자열을 만들 수 있다고 가정 할 수 없습니다. InputStreamReader를 사용하거나 전체 데이터를 먼저 배열로 읽으십시오 (분명히 작동하지 않을 것입니다). 큰 파일). 그러나, 그것은 XP에서 작동하는 것 같기 때문에, 나는 이것이 아마도이 특정한 경우에 당신의 문제가 아니라고 모험 할 것입니다.

    6

    @Joel - your own answer은 문제가 운영 체제의 기본 인코딩 (UTF-8, Java가 선택됨)과 터미널이 사용하는 인코딩 (ISO-8859-1) 사이의 차이점임을 확인합니다. 기본적으로

    public static void main(String[] args) throws IOException { 
        byte[] data = { (byte) 0xF4 }; 
        String decoded = new String(data, "ISO-8859-1"); 
        if (!"\u00f4".equals(decoded)) { 
         throw new IllegalStateException(); 
        } 
    
        // write default charset 
        System.out.println(Charset.defaultCharset()); 
    
        // dump bytes to stdout 
        System.out.write(data); 
    
        // will encode to default charset when converting to bytes 
        System.out.println(decoded); 
    } 
    

    , 내 우분투 (8.04) 터미널은 UTF-8 인코딩을 사용

    이 코드를 생각해 보자. 이 인코딩이 인쇄된다 :

    UTF-8 & #
    x00F4; I는 ISO 8859에 단말의 부호화를 전환하면

    ,이 인쇄되어

    UTF-8 & #
    x00F4; & # x00C3; & # x00B4; 두 경우

    는 동일한 바이트 Java 프로그램에 의해 방출되고 :

    5554 462d 380a f4c3 b40a 
    

    유일한 차이점은 단말기가 수신 바이트를 해석하는 방법이다. ISO 8859-1, & # x00F4; 0xF4로 인코딩됩니다. UTF-8, & # x00F4; 0xC3B4로 인코딩됩니다. 다른 문자는 두 인코딩 모두에 공통적입니다.

    +0

    나는 5554 462d 380a f4c3 b40a' 덤프는 무엇입니까? 확실히'System.out.write (data)'호출이 아닌가? –

    +1

    @Mr_and_Mrs_D JRE가 'System.out'을 세 번 호출하여 장치 (STDOUT)에 쓴 바이트입니다. '0A' 바이트는'println'에 의해 쓰여진 개행을 표시합니다. _ 질문 작성자가 작성한 답변이 삭제 되었기 때문에 읽지 못했지만 많이 읽을 수 있다고 생각합니다 ._ – McDowell

    +0

    다음 주셔서 감사합니다 - 삭제 된 이후 작성자의 답변이 있음을 이해했습니다 - 읽을 수 없습니다 - 감사 :) –