NIO API vs. Old IO API

Status
Nicht offen für weitere Antworten.

GNUke

Neues Mitglied
Hallo,

Echt tolles Forum hier (auch noch in deutsch). Deshalb hier meine erste Frage:

Ich arbeite gerade an einem XML-Parser, der sowohl das alte IO API (java.io.*), als auch das neue (java.nio.*) als Eingabequelle für die Zeichen untersützt.
Die Vorgehensweise zum Lesen beim alten API ist folgende:

- Per Reader.read() in einen char-Puffer (Gr.: 2048) füllen
- und das das Zeichen an der jeweiligen Position zurückgeben.

Mit NIO:

- Mit einem FileChannel einen ByteBuffer (Gr.: 2048) füllen,
- den ByteBuffer mit einem CharsetDecoder in einen CharBuffer (Gr.: 2048) decodieren
- und mit CharBuffer.get() das jeweilige Zeichen zurückgeben.

Das funktioniert alles perfekt, aber das Problem ist, dass das neue IO API doch spürbar lansamer ist (old IO: ca. 60-70ms , new IO: 110-120ms bei einer XML-Dateigröße von 444 kByte mit JRE 1.4.2_04). Da ich den Zeichensatz der Datei eventl. erst durch den XML-Prolog (bspw. <?xml version="1.1" encoding="windows-1252" ?>) bestimmen kann, muss ich diesen auch nach der Erstellung der Reader- bzw. FileChannel-Objekte ändern können, was leider mit dem alten IO API nicht funktioniert :( .

Wo liegt der Performance-Fresser (NIO soll ja doch scheller sein!) oder was habe ich falsch gemacht?

THX,

GNUke
 

GNUke

Neues Mitglied
Um den Performance-Vergleich zu verdeutlichen, sind im folgenden beide Klassen für beide APIs aufgelistet (peek() liefert das aktuelle Zeichen zurück; pop() liefert das aktuelle Zeichen und setzt den Zeiger auf das nächste Zeichen; setCharset() setzt den Zeichensatz, funktioniert jedoch nur bei java.nio-API [s.a. oben]):

Für java.io-API:

Code:
public class ReaderCharSource extends CharSource {
    private Reader reader;
    private char[] buffer;
    private int    offset;
    private int    limit;
    
    public ReaderCharSource(Reader reader, int bufferSize) {
        if (bufferSize < 8) throw new IllegalArgumentException();
        
        this.reader = reader;
        
        buffer      = new char[bufferSize];
        offset      = 0;
        limit       = 0;
    }
    
    public char peek() throws IOException {
        if (offset == limit) {
            limit  = reader.read(buffer, 0, buffer.length);
            offset = 0;
            
            if (limit == -1) throw new IndexOutOfBoundsException();
        }
        
        return buffer[offset];
    }
    
    public char pop() throws IOException {
        char c = peek();
        
        offset++;
        
        if (c == '\r' || c == '\n') {
            if (c == '\r' && peek() == '\n') {
                offset++;
            }
            
            line++;
            column = 1;
        } else {        
            column++;
        }
        
        return c;
    }
    
    public void setCharset(String charset) {
        //////////////////////////////////////
        // Funktioniert nicht mit java.io ! //
        //////////////////////////////////////
    }
    
}

Für java.nio-API:

Code:
public class ChannelCharSource extends CharSource {
    private ByteBuffer          byteBuffer;
    private CharBuffer          charBuffer;
    private CharsetDecoder      decoder;
    private ReadableByteChannel channel;
    
    public ChannelCharSource(ReadableByteChannel channel, String charset, int bufferSize) {
        if (bufferSize < 8) throw new IllegalArgumentException();
        
        this.channel = channel;
        
        byteBuffer = ByteBuffer.allocate(bufferSize);
        charBuffer = CharBuffer.allocate(bufferSize);
        decoder    = Charset.forName(charset).newDecoder().onMalformedInput(CodingErrorAction.REPORT);
        
        charBuffer.limit(0);
        decoder.reset();
    }
    
    public char peek() throws IOException {
        if (!charBuffer.hasRemaining()) {
            byteBuffer.clear();
            charBuffer.clear();
            channel.read(byteBuffer);
            byteBuffer.flip();
            decoder.decode(byteBuffer, charBuffer, false);
            charBuffer.flip();
        }
        
        return charBuffer.get(charBuffer.position());
    }
    
    public char pop() throws IOException {
        char c = peek();
        
        charBuffer.position(charBuffer.position() + 1);
        
        if (c == '\r' || c == '\n') {
            if (c == '\r' && peek() == '\n') {
                charBuffer.position(charBuffer.position() + 1);
            }
            
            line++;
            column = 1;
        } else {        
            column++;
        }
        
        return c;
    }
    
    public void setCharset(String charsetName) {
        Charset charset = Charset.forName(charsetName);
        
        if (!charset.equals(decoder.charset())) {
            decoder = charset.newDecoder().onMalformedInput(CodingErrorAction.REPORT);
        
            decoder.reset();
            decoder.decode(byteBuffer, charBuffer, false);
        }
    }
}

Falls ihr wie ich nicht wisst, wo der Performancefresser sitzt, postet doch einfach eure Erfahrungen mit dem neuen API!

THX,

GNUke
 

akira

Bekanntes Mitglied
Hi,

ich schiebe den Thread nochmal hoch, da mich die Lösung dieser Frage sehr interessieren würde.

Hintergrund ist der, daß ich eine eigene Properties-ähnliche Klasse schreiben möchte (siehe auch http://www.java-forum.org/de/viewtopic.php?t=11046), die auf einer <String,String>Map beruht und zum Einlesen das nio verwendet. Ich konnte per google kein Beispiel finden, wie man eine einfache Textdatei per nio lädt.

Bei der Recherche im Forum habe ich diesen Thread gelesen und mich gefragt, ob der Umstieg auf nio wirklich lohnt?
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben