InputStreamReader缓冲问题

Mik*_*e Q 11 java buffer decode character-encoding inputstreamreader

我正在从一个文件中读取数据,遗憾的是,这种文件有两种类型的字符编码.

有一个标题和一个正文.标头始终为ASCII,并定义正文编码的字符集.

标头不是固定长度,必须通过解析器运行以确定其内容/长度.

该文件也可能非常大,所以我需要避免将整个内容带入内存.

所以我开始使用单个InputStream.我最初使用带有ASCII的InputStreamReader包装它并解码标头并提取主体的字符集.都好.

然后我创建一个具有正确字符集的新InputStreamReader,将其放在同一个InputStream上并开始尝试读取正文.

不幸的是,javadoc证实了这一点,即InputStreamReader可能会选择提前读取以达到效率目的.因此,标题的阅读会咀嚼身体的一部分/全部.

有没有人有解决这个问题的建议?会手动创建一个CharsetDecoder并一次输入一个字节但是一个好主意(可能包含在自定义的Reader实现中吗?)

提前致谢.

编辑:我的最终解决方案是编写一个没有缓冲的InputStreamReader,以确保我可以解析标题而不会咀嚼身体的一部分.虽然这不是非常有效,但我使用BufferedInputStream包装原始InputStream,因此它不会成为问题.

// An InputStreamReader that only consumes as many bytes as is necessary
// It does not do any read-ahead.
public class InputStreamReaderUnbuffered extends Reader
{
    private final CharsetDecoder charsetDecoder;
    private final InputStream inputStream;
    private final ByteBuffer byteBuffer = ByteBuffer.allocate( 1 );

    public InputStreamReaderUnbuffered( InputStream inputStream, Charset charset )
    {
        this.inputStream = inputStream;
        charsetDecoder = charset.newDecoder();
    }

    @Override
    public int read() throws IOException
    {
        boolean middleOfReading = false;

        while ( true )
        {
            int b = inputStream.read();

            if ( b == -1 )
            {
                if ( middleOfReading )
                    throw new IOException( "Unexpected end of stream, byte truncated" );

                return -1;
            }

            byteBuffer.clear();
            byteBuffer.put( (byte)b );
            byteBuffer.flip();

            CharBuffer charBuffer = charsetDecoder.decode( byteBuffer );

            // although this is theoretically possible this would violate the unbuffered nature
            // of this class so we throw an exception
            if ( charBuffer.length() > 1 )
                throw new IOException( "Decoded multiple characters from one byte!" );

            if ( charBuffer.length() == 1 )
                return charBuffer.get();

            middleOfReading = true;
        }
    }

    public int read( char[] cbuf, int off, int len ) throws IOException
    {
        for ( int i = 0; i < len; i++ )
        {
            int ch = read();

            if ( ch == -1 )
                return i == 0 ? -1 : i;

            cbuf[ i ] = (char)ch;
        }

        return len;
    }

    public void close() throws IOException
    {
        inputStream.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

bru*_*nde 3

为什么不使用2s InputStream?一个用于读取标题,另一个用于读取正文。

第二个InputStream应该是skip标头字节。