Чтение файла ASCII с помощью FileChannel и ByteArrays

У меня есть следующий код:

        String inputFile = "somefile.txt";
        FileInputStream in = new FileInputStream(inputFile);
        FileChannel ch = in.getChannel();
        ByteBuffer buf = ByteBuffer.allocateDirect(BUFSIZE);  // BUFSIZE = 256

        /* read the file into a buffer, 256 bytes at a time */
        int rd;
        while ( (rd = ch.read( buf )) != -1 ) {
            buf.rewind();
            for ( int i = 0; i < rd/2; i++ ) {
                /* print each character */
                System.out.print(buf.getChar());
            }
            buf.clear();
        }

Но символы отображаются на ?. Это как-то связано с Java, использующей символы Unicode? Как это исправить?


person Jake    schedule 18.09.2008    source источник


Ответы (6)


Вы должны знать кодировку файла, а затем декодировать ByteBuffer в CharBuffer, используя эту кодировку. Предполагая, что файл ASCII:

import java.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class Buffer
{
    public static void main(String args[]) throws Exception
    {
        String inputFile = "somefile";
        FileInputStream in = new FileInputStream(inputFile);
        FileChannel ch = in.getChannel();
        ByteBuffer buf = ByteBuffer.allocateDirect(BUFSIZE);  // BUFSIZE = 256

        Charset cs = Charset.forName("ASCII"); // Or whatever encoding you want

        /* read the file into a buffer, 256 bytes at a time */
        int rd;
        while ( (rd = ch.read( buf )) != -1 ) {
            buf.rewind();
            CharBuffer chbuf = cs.decode(buf);
            for ( int i = 0; i < chbuf.length(); i++ ) {
                /* print each character */
                System.out.print(chbuf.get());
            }
            buf.clear();
        }
    }
}
person jliszka    schedule 18.09.2008
comment
Если вы хотите избежать вывода каждого символа отдельно, вы можете просто использовать buf.flip() вместо buf.rewind() и передать весь chbuf в System.out.print() - person hertzsprung; 29.07.2011

buf.getChar() ожидает 2 байта на символ, но вы сохраняете только 1. Используйте:

 System.out.print((char) buf.get());
person Craig Day    schedule 18.09.2008

Изменение оператора печати на:

System.out.print((char)buf.get());

Кажется, помогает.

person jjnguy    schedule 18.09.2008

В зависимости от кодировки файла somefile.txt символ может состоять не из двух байтов. Эта страница содержит дополнительную информацию о том, как читать потоки с правильной кодировкой.

Облом в том, что файловая система не сообщает вам кодировку файла, потому что она не знает. Насколько это касается, это просто набор байтов. Вы должны либо найти какой-то способ передать кодировку программе, каким-то образом определить ее, либо (если возможно) всегда следить за тем, чтобы кодировка была одинаковой (например, UTF-8).

person Robert J. Walker    schedule 18.09.2008

Есть ли особая причина, по которой вы читаете файл так, как вы это делаете?

Если вы читаете файл ASCII, вам действительно следует использовать Reader.

Я бы сделал что-то вроде:

File inputFile = new File("somefile.txt");
BufferedReader reader = new BufferedReader(new FileReader(inputFile));

А затем используйте либо readLine, либо что-то подобное, чтобы фактически прочитать данные!

person Community    schedule 18.09.2008
comment
У меня огромное количество данных, и я пытаюсь оптимизировать время чтения. Ссылка: nadeausoftware.com/articles/2008/02/ - person Jake; 18.09.2008
comment
@Jake, в вашем примере вы читаете байты, а затем декодируете символы. Почему вы предполагаете, что это быстрее, чем использование BufferedReader? Интересные тесты, на которые вы указываете, не читают символы. - person Lluis Martinez; 16.03.2010

Да, это Юникод.

Если в вашем файле 14 символов, вы получите только 7 '?'.

Ожидается решение. Еще думаю.

person Burkhard    schedule 18.09.2008