Java FileReader 인코딩 문제


130

java.io.FileReader를 사용하여 일부 텍스트 파일을 읽고 문자열로 변환하려고 시도했지만 결과가 잘못 인코딩되어 읽을 수 없다는 것을 알았습니다.

내 환경은 다음과 같습니다.

  • Windows 2003, OS 인코딩 : CP1252

  • 자바 5.0

내 파일은 UTF-8로 인코딩되거나 CP1252로 인코딩되며 일부 (UTF-8로 인코딩 된 파일)에는 중국어 (라틴 문자가 아닌) 문자가 포함될 수 있습니다.

다음 코드를 사용하여 작업을 수행합니다.

   private static String readFileAsString(String filePath)
    throws java.io.IOException{
        StringBuffer fileData = new StringBuffer(1000);
        FileReader reader = new FileReader(filePath);
        //System.out.println(reader.getEncoding());
        BufferedReader reader = new BufferedReader(reader);
        char[] buf = new char[1024];
        int numRead=0;
        while((numRead=reader.read(buf)) != -1){
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
            buf = new char[1024];
        }
        reader.close();
        return fileData.toString();
    }

위의 코드는 작동하지 않습니다. 텍스트가 UTF-8로 인코딩 된 경우에도 FileReader의 인코딩이 CP1252라는 것을 알았습니다. 그러나 java.io.FileReader의 JavaDoc은 다음과 같이 말합니다.

이 클래스의 생성자는 기본 문자 인코딩과 기본 바이트 버퍼 크기가 적절하다고 가정합니다.

FileReader를 사용하는 경우 직접 문자 인코딩을 설정할 필요가 없다는 의미입니까? 그러나 현재 잘못 인코딩 된 데이터를 얻었습니다. situtaion을 처리하는 올바른 방법은 무엇입니까? 감사.


또한 루프 내에서 String.valueOf ()를 풀고 StringBuffer.append (char [], int, int)를 직접 사용해야합니다. 이것은 char []의 많은 복사를 저장합니다. 또한 StringBuffer를 StringBuilder로 교체하십시오. '아무것도 당신의 질문에 관한 것이 아닙니다.
— Joachim Sauer 2016 년

1
나는 그것을 말하기 싫어하지만 붙여 넣은 부분 직후에 JavaDoc을 읽었습니까? "이 값을 직접 지정하려면 FileInputStream에 InputStreamReader를 구성하십시오."라는 부분이 있습니까?
— Powerlord

귀하의 의견에 감사드립니다. 실제로 JavaDoc을 읽었지만 확실하지 않은 것은 이러한 값을 직접 지정해야하는지 여부와 "FileInputStream에서 InputStreamReader 구성"으로 전환하는 것입니다.
— nybon

예, 파일이 플랫폼 기본 인코딩 이외의 파일임을 알고 있으면 사용할 파일을 InputStreamReader에 알려야합니다.
— Alan Moore

답변:


248

예, 읽으려는 파일 의 인코딩을 지정해야합니다 .

예, 읽으려는 파일의 인코딩 을 알고 있어야 합니다.

아니요, 주어진 "일반 텍스트"파일의 인코딩 을 추측 하는 일반적인 방법은 없습니다 .

하나의 인수 생성자는FileReader 항상 플랫폼 기본 인코딩을 사용하는데 이는 일반적 으로 나쁜 생각 입니다.

Java 11 FileReader은 인코딩을 허용하는 생성자를 얻었으므로 : new FileReader(file, charset)및 new FileReader(fileName, charset).

이전 버전의 Java에서는을 사용해야 합니다.new InputStreamReader(new FileInputStream(pathToFile), <encoding>)


1
InputStream은 = new FileInputStream (파일 이름)입니다. 여기에 내가 러시아어 파일 이름으로 오류 파일을 찾을 수 없습니다 오류가 발생했습니다
— Bhanu 샤르마에게

3
InputStreamReader 사용을 제안하는 경우 +1이지만 코드 블록에 링크를 사용하면 코드를 복사하여 붙여 넣기가 어려워집니다 (변경 될 수있는 경우). thx
— Ferrybig

1
인코딩에서 "UTF-8"또는 "UTF8"입니까? 에 따르면 인코딩에서 Java SE 참조 하기 때문에, InputStreamReaderA는 java.io클래스, 그것은 "UTF8"것입니까?
— NobleUplift

9
@NobleUplift : 가장 안전한 방법은 엉망이 StandardCharsets.UTF_8될 가능성이 없다는 것입니다 ;-) 그러나 네, 문자열 "UTF8"을 사용하면 정확합니다 (두 가지 방법을 모두 수용한다는 것을 기억하지만).
— Joachim Sauer

1
@JoachimSauer 사실, 이것은 Byte Order Mark바이트 순서 설정과 함께 .. 의 목적 중 하나입니다 ! :) 따라서 Java의 FileReader가 그러한 BOM이있는 UTF-16을 자동으로 감지 할 수 없다는 것이 이상합니다. 실제로 나는 한 번 UnicodeFileReader정확히 그 일을했습니다. 불행히도 비공개 소스이지만 Google에는 매우 유사한 UnicodeReader 가 있습니다.
— Stijn de Witt

79

FileReader Java의 플랫폼 기본 인코딩을 사용합니다.이 인코딩은 실행중인 컴퓨터의 시스템 설정에 따라 다르며 일반적으로 해당 로캘의 사용자에게 가장 인기있는 인코딩입니다.

이 "최상의 추측"이 올바르지 않으면 인코딩을 명시 적으로 지정해야합니다. 불행히도 FileReader이것을 허용하지 않습니다 (API의 주요 감독). 대신 new InputStreamReader(new FileInputStream(filePath), encoding)파일에 대한 메타 데이터에서 인코딩 을 사용 하고 이상적으로 가져와야합니다.


24
"API에 대한 주요 감독"-이 설명에 감사드립니다-왜 내가 만든 생성자를 찾을 수 없는지 궁금했습니다! 건배 John
— monojohnny

@Bhanu Sharma : 그것은 다른 수준의 인코딩 문제이며, 파일 이름을 어디에서 가져 왔는지 확인하고, 컴파일러가 사용하는 인코딩을 하드 코딩했는지 확인하십시오.
— Michael Borgwardt

1
@BhanuSharma : 파일 이름 인코딩 문제는이 질문과 관련이 없습니다. 기존의 많은“유니 코드 파일 이름이 Java에서 작동하지 않는 이유”질문 중 하나를 참조하십시오. 스포일러 : FileReader와 같은 java.io API는 Windows에서 유니 코드를 지원할 수없는 C 표준 라이브러리 파일 시스템 호출을 사용합니다. 대신 java.nio 사용을 고려하십시오.
— bobince

1
" FileReaderJava 플랫폼 기본 인코딩을 사용합니다.이 인코딩은 실행중인 컴퓨터의 시스템 설정에 따라 다르며 일반적으로 해당 로캘의 사용자들 사이에서 가장 인기있는 인코딩입니다." 나는 그렇게 말하지 않을 것입니다. 최소한 Windows. 기묘한 기술적 / 역사적 이유로 인해 JVM은 유니 코드가 Windows에서 '모든 새 애플리케이션'에 권장되는 인코딩 이라는 사실을 무시하고 레거시 앱의 폴백으로 구성된 레거시 인코딩 이 '플랫폼 기본값'인 것처럼 항상 작동 합니다.
— Stijn de Witt

6
심지어 Java 앱이 파일 / 스트림 / 리소스를 읽거나 쓸 때마다 인코딩을 명시 적으로 지정 하지 않으면 안정적 으로 작동 할 수 없기 때문에 깨진 것 입니다.
— Stijn de Witt


6

Java 7+ doc의 경우 다음을 사용할 수 있습니다.

BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);

여기에 모든 Charsets doc가 있습니다

예를 들어 파일이 CP1252에있는 경우이 방법을 사용하십시오.

Charset.forName("windows-1252");

IO 및 NIO doc 모두에 대한 Java 인코딩의 다른 표준 이름은 다음과 같습니다.

파일에 정확히 인코딩되어 있는지 모르는 경우 Google 의이 도구와 같은 타사 라이브러리를 사용하면 상당히 깔끔합니다.


1

InputStreamReader를 사용하는 FileInputStream은 FileReader를 직접 사용하는 것보다 낫습니다. 후자는 인코딩 문자 세트를 지정할 수 없기 때문입니다.

다음은 BufferedReader, FileInputStream 및 InputStreamReader를 함께 사용하여 파일에서 행을 읽을 수있는 예제입니다.

List<String> words = new ArrayList<>();
List<String> meanings = new ArrayList<>();
public void readAll( ) throws IOException{
    String fileName = "College_Grade4.txt";
    String charset = "UTF-8";
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(
            new FileInputStream(fileName), charset)); 

    String line; 
    while ((line = reader.readLine()) != null) { 
        line = line.trim();
        if( line.length() == 0 ) continue;
        int idx = line.indexOf("\t");
        words.add( line.substring(0, idx ));
        meanings.add( line.substring(idx+1));
    } 
    reader.close();
}

0

키릴 자모와 같은 라틴 언어의 다른 경우 다음과 같이 사용할 수 있습니다.

FileReader fr = new FileReader("src/text.txt", StandardCharsets.UTF_8);

.txt파일이 UTF-8(기본이 아닌 ANSI) 형식 으로 저장되어 있는지 확인하십시오 . 건배!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.