Java FileReader kodlama sorunu


130

Bazı metin dosyalarını okumak ve bir dizeye dönüştürmek için java.io.FileReader'ı kullanmayı denedim, ancak sonucun yanlış kodlandığını ve hiç okunamaz olduğunu buldum.

İşte ortamım:

  • Windows 2003, işletim sistemi kodlaması: CP1252

  • Java 5.0

Dosyalarım UTF-8 kodlu veya CP1252 kodlu ve bazıları (UTF-8 kodlu dosyalar) Çince (Latin olmayan) karakterler içerebilir.

İşimi yapmak için aşağıdaki kodu kullanıyorum:

   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();
    }

Yukarıdaki kod çalışmıyor. Metin UTF-8 kodlu olsa bile Dosya Okuyucunun kodlamasının CP1252 olduğunu buldum. Ancak java.io.FileReader'ın JavaDoc'u şunu söylüyor:

Bu sınıfın yapıcıları, varsayılan karakter kodlamasının ve varsayılan bayt arabellek boyutunun uygun olduğunu varsayar.

Bu, FileReader kullanıyorsam karakter kodlamasını kendim ayarlamam gerekmediği anlamına mı geliyor? Ama şu anda yanlış kodlanmış veriler aldım, durumumla başa çıkmanın doğru yolu nedir? Teşekkürler.


Döngünün içindeki String.valueOf () öğesini de gevşetmeli ve doğrudan StringBuffer.append (char [], int, int) kullanmalısınız. Bu, char [] 'ın birçok kopyasını kurtarır. Ayrıca StringBuffer'ı StringBuilder ile değiştirin. Yine de bunların hiçbiri sorunuzla ilgili değil.
Joachim Sauer

1
Bunu söylemekten nefret ediyorum ama yapıştırdığınız bölümden hemen sonra JavaDoc'u okudunuz mu? Biliyorsunuz, "Bu değerleri kendiniz belirlemek için, FileInputStream üzerinde bir InputStreamReader oluşturun."
Powerlord

Yorumunuz için teşekkürler, aslında JavaDoc'u okudum, ancak bu değerleri kendim belirtmem ve "FileInputStream üzerinde bir InputStreamReader oluştur" a geçip geçmemem konusunda emin olmadığım şey.
nybon

Evet, dosyanın platform varsayılan kodlamasından farklı bir şey olduğunu biliyorsanız, InputStreamReader'a hangisinin kullanılacağını söylemeniz gerekir.
Alan Moore

Yanıtlar:


248

Evet, okumak istediğiniz dosyanın kodlamasını belirtmeniz gerekiyor .

Evet, bu araçlar size zorunda biliyorum Okumak istediğiniz dosyanın kodlamasını.

Hayır, herhangi bir "düz metin" dosyasının kodlamasını tahmin etmenin genel bir yolu yoktur .

Tek bağımsız değişkenli yapıcılarFileReader her zaman platform varsayılan kodlamasını kullanır ve bu genellikle kötü bir fikirdir .

Java 11 FileReaderayrıca bir kodlamayı kabul eden kurucular kazandığından: new FileReader(file, charset)ve new FileReader(fileName, charset).

Java'nın önceki sürümlerinde kullanmanız gerekir .new InputStreamReader(new FileInputStream(pathToFile), <encoding>)


1
InputStream = new FileInputStream (dosya adı); burada Rus dosya adında dosya bulunamadı hatası aldım
Bhanu Sharma

3
InputStreamReader'ı kullanma önerisi için +1, ancak kod bloklarındaki bağlantıları kullanmak, kodu kopyalayıp yapıştırmayı zorlaştırır, eğer bu değiştirilebilirse, thx
Ferrybig

1
Kodlamalarda "UTF-8" mi yoksa "UTF8" mi olur? Göre kodlama Java SE referans beri, InputStreamReaderbir olan java.iosınıf, bu "UTF8" olurdu?
NobleUplift

9
@NobleUplift: En güvenli bahis StandardCharsets.UTF_8, orada yanlış yazmanın hiç şansı yok ;-) Ama evet, dizeyle gidersen "UTF8"doğru olur (her iki yolu da kabul edeceğini hatırlıyorum gibi görünüyor).
Joachim Sauer

1
@JoachimSauer Aslında bu, Byte Order Markbayt düzeninin oluşturulmasıyla birlikte .. peki .. amaçlarından biridir ! :) Bu nedenle, Java'nın Dosya Okuyucusunun böyle bir BOM'a sahip UTF-16'yı otomatik olarak tespit edememesini garip buluyorum ... Aslında bir keresinde UnicodeFileReadertam olarak bunu yapan bir yazdım . Maalesef kapalı kaynak, ancak Google'ın çok benzer olan UnicodeReader'ı var.
Stijn de Witt

79

FileReader Java'nın, üzerinde çalıştığı bilgisayarın sistem ayarlarına bağlı olan ve genellikle o yerel ayardaki kullanıcılar arasında en popüler kodlama olan platform varsayılan kodlamasını kullanır.

Bu "en iyi tahmin" doğru değilse, kodlamayı açıkça belirtmeniz gerekir. Ne yazık ki FileReaderbuna izin vermiyor (API'de büyük gözetim). Bunun yerine, new InputStreamReader(new FileInputStream(filePath), encoding)kodlamayı dosya hakkındaki meta verilerden kullanmanız ve ideal olarak almanız gerekir.


24
"API'de büyük gözetim" - bu açıklama için teşekkürler - peşinde olduğum kurucuyu neden bulamadığımı merak ediyordum! Şerefe John
monojohnny

@Bhanu Sharma: Bu farklı bir düzeyde bir kodlama sorunu, dosya adını nereden aldığınızı ve derleyicinin kullandığı kodlamanın kodlanmış olup olmadığını kontrol edin.
Michael Borgwardt

1
@BhanuSharma: dosya adı kodlama sorunlarının bu soruyla hiçbir ilgisi yoktur. Mevcut birçok "Unicode dosya adları Java'da neden çalışmıyor" sorusundan birine bakın. Spoiler: FileReader gibi java.io API'leri, Windows'ta Unicode'u destekleyemeyen C standart kitaplık dosya sistemi çağrılarını kullanır; bunun yerine java.nio kullanmayı düşünün.
bobince

1
" FileReaderJava'nın, üzerinde çalıştığı bilgisayarın sistem ayarlarına bağlı olan ve genellikle o yerel ayardaki kullanıcılar arasında en popüler kodlama olan platform varsayılan kodlamasını kullanır." Ben öyle demezdim. En azından Windows. Bazı garip teknik / tarihsel nedenlerden ötürü, JVM, Unicode'un Windows'ta 'tüm yeni uygulamalar' için önerilen kodlama olduğu gerçeğini göz ardı eder ve bunun yerine her zaman eski uygulamalar için yedek olarak yapılandırılan eski kodlama 'platform varsayılanı' gibi davranır .
Stijn de Witt

6
Hatta Java uygulamanız dosyaları / akışları / kaynakları her okuduğunda veya yazarken kodlamaları açıkça belirtmiyorsa, bozuk olduğunu çünkü o zaman güvenilir bir şekilde çalışamayacağını söyleyecek kadar ileri gidebilirim .
Stijn de Witt

8

Java 11'den beri şunları kullanabilirsiniz:

public FileReader(String fileName, Charset charset) throws IOException;

6

Java 7+ dokümanı için şunu kullanabilirsiniz:

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

İşte bütün Charsets olan doc

Örneğin, dosyanız CP1252'de ise bu yöntemi kullanın

Charset.forName("windows-1252");

Hem IO hem de NIO doc için Java kodlamaları için diğer kanonik isimler.

Bir dosyada sahip olduğunuzu tam olarak kodlamayı bilmiyorsanız, Google'ın bu aracı gibi oldukça düzgün çalışan bazı üçüncü taraf kitaplarını kullanabilirsiniz .


1

InputStreamReader ile FileInputStream, FileReader'ı doğrudan kullanmaktan daha iyidir, çünkü ikincisi kodlama karakter kümesini belirlemenize izin vermez.

Bir dosyadan satırları okuyabilmeniz için BufferedReader, FileInputStream ve InputStreamReader'ın birlikte kullanıldığı bir örnek aşağıda verilmiştir.

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

Bir başkası için Latin dilleri, örneğin Kiril alfabesi şöyle bir şey kullanabilirsiniz:

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

ve .txtdosyanızın UTF-8(varsayılan olarak değil ANSI) formatta kaydedildiğinden emin olun . Şerefe!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.