2012-12-18 38 views
1

我試圖讀取被編碼爲UTF-16文件的(日文)文件。Java Charset InputStreamReader,文件通道差異

當我使用的InputStreamReader用的字符集閱讀「UTF-16" 的文件被正確地讀:

try { 
     InputStreamReader read = new InputStreamReader(new FileInputStream("JapanTest.txt"), "UTF-16"); 
     BufferedReader in = new BufferedReader(read); 
     String str; 
     while((str=in.readLine())!=null){   
      System.out.println(str); 
    } 
    in.close(); 
}catch (Exception e){ 
    System.out.println(e); 
} 

然而,當我使用文件頻道和讀取從一個字節數組的字符串AREN」噸總是正確地轉換:

File f = new File("JapanTest.txt"); 
    fis = new FileInputStream(f); 
    channel = fis.getChannel(); 
    MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0L, channel.size()); 
    buffer.position(0); 
    int get = Math.min(buffer.remaining(), 1024); 
    byte[] barray = new byte[1024]; 
    buffer.get(barray, 0, get); 
    CharSet charSet = Charset.forName("UTF-16"); 
    //endOfLinePos is a calculated value and defines the number of bytes to read 
    rowString = new String(barray, 0, endOfLinePos, charSet);    
    System.out.println(rowString); 

我發現的問題是,如果我遞增MappedByteBuffer的位置我只能正確地讀取的字符,如果是MappedByteBuffer爲0的位置,然後讀出的字節數進一個字節數組,然後轉換爲在使用字符集UTF-16時,字節不能正確轉換。如果文件以UTF-8編碼,我還沒有遇到這個問題,那麼這僅僅是UTF-16的一個問題?

更多詳細信息: 我需要能夠從文件通道讀取任何行,所以爲此我建立一個行結束字節位置的列表,然後使用這些位置可以獲得任何給定的字節行,然後將它們轉換爲字符串。

+1

可能'endOfLinePos'計算錯誤;如果它是一個奇數,這很麻煩,因爲UTF-16需要偶數個字節。 – irreputable

+0

我懷疑可能是1024個字符組在「中間」分割了一個UTF-16字符。 –

回答

1

UTF-16的代碼單元是2個字節,而不是像UTF-8這樣的字節。模式和單字節代碼單元長度使UTF-8自同步;它可以在任何時候正確讀取,如果它是一個連續字節,它可以回溯或僅丟失一個字符。

使用UTF-16,您必須始終處理字節對,您不能開始讀取奇數字節或停止讀取奇數字節。你也必須知道endianess,並且當不在文件的開始讀取時使用UTF-16LE或UTF-16BE,因爲不會有BOM。

您也可以將文件編碼爲UTF-8。

1

可能,InputStreamReader做了一些轉換,正常的new String(...)沒有。作爲解決方法(並驗證這個假設),您可以嘗試從通道讀取數據,如new InputStreamReader(new ByteArrayInputStream(barray))

編輯:忘了:) - Channels.newReader()將是要走的路。

+0

我需要能夠從文件通道讀取任何行,所以爲此我建立一個行結束字節位置的列表,然後使用這些位置來獲取任意給定行的字節,然後將它們轉換爲串。 – joechip

+0

用於按行處理['LineNumberReader'](http://download.java.net/jdk7/archive/b123/docs/api/java/io/LineNumberReader.html)。 – JimmyB

+0

正確 - 但我想使用文件通道,因爲這些文件可能很大,因此會節省大量內存。 – joechip