Problema de búfer de InputStreamReader

Estoy leyendo datos de un archivo que tiene, por desgracia, dos tipos de codificación de caracteres.

Hay un encabezado y un cuerpo. El encabezado siempre está en ASCII y define el juego de caracteres en el que está codificado el cuerpo.

El encabezado no tiene una longitud fija y debe ejecutarse a través de un analizador para determinar su contenido / longitud.

El archivo también puede ser bastante grande, por lo que debo evitar traer todo el contenido a la memoria.

Entonces comencé con un solo InputStream. Inicialmente lo envuelvo con un InputStreamReader con ASCII y decodifico el encabezado y extraigo el conjunto de caracteres para el cuerpo. Todo bien.

Luego creo un nuevo InputStreamReader con el juego de caracteres correcto, lo coloco sobre el mismo InputStream y empiezo a intentar leer el cuerpo.

Desafortunadamente, parece que javadoc confirma esto, que InputStreamReader puede elegir leer con anticipación para fines de eficiencia. Entonces, la lectura del encabezado mastica parte / todo el cuerpo.

¿Alguien tiene alguna sugerencia para solucionar este problema? ¿Crear un CharsetDecoder manualmente y alimentarlo en un byte a la vez es una buena idea (posiblemente envuelto en una implementación personalizada de Reader?)

Gracias por adelantado.

EDITAR: Mi solución final fue escribir un InputStreamReader que no tenga almacenamiento en búfer para garantizar que pueda analizar el encabezado sin masticar parte del cuerpo. Aunque esto no es terriblemente eficiente, envuelvo el InputStream sin procesar con un BufferedInputStream para que no sea un problema.

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

Respuestas a la pregunta(6)

Su respuesta a la pregunta