2

私が欲しいのは、次のようなものになってしまうことです。

public class InterleavedBufferedReader extends BufferedReader {
...
}

そしてそれを次のように使用します:

Reader[3] readers = ...; // three readers
InterleavedBufferedReader ibr = new InterleavedBufferedReader(readers);

ibr.readLine();  // this returns the first line of Reader 1
ibr.readLine();  // this returns the first line of Reader 2
ibr.readLine();  // this returns the first line of Reader 3

ibr.readLine();  // this returns the second line of Reader 1
ibr.readLine();  // this returns the second line of Reader 2
ibr.readLine();  // hey, Reader 3 had no more lines, return the third line of Reader 1

私が試したこと(ダメ、私は知っている、それが私がここにいる理由です):

public class InterleavedBufferedReader extends BufferedReader {

    static private int current = 0;
    private BufferedReader[] buffers;


    public InterleavedBufferedReader(BufferedReader[] in) {
        super(new StringReader("dummy"));
        buffers = in;
    }

    public InterleavedBufferedReader(Reader[] in) {
        super(new StringReader("dummy"));
        buffers = new BufferedReader[in.length];
        for (int i=0 ; i < in.length ; i++)
            buffers[i] = new BufferedReader(in[i]);
    }

    @Override
    public String readLine() throws IOException {
        int start = current;
        String line = null;
        while ((line = buffers[current].readLine()) == null) {
            current = (current+1) % buffers.length;
            if (current == start)
                return null;
        }       
        current = (current+1) % buffers.length;
        return line;

    }

    @Override 
    public void close() throws IOException {
        for (int i=0;  i < buffers.length; i++)
            buffers[i].close();
    }
}

コメント:

  • インターリーブreadLine()は実際に機能します!
  • おそらく私は拡張するべきではありませんBufferedReader。私はそれに管理するためのダミーのリーダーを与えることを余儀なくされます、さもなければそれはコンパイルさえしません。その間、readLine()メソッドをオーバーライドして、子リーダーで呼び出すようにします。read()しかし、他のメソッドは、実際には私のダミーリーダーを参照するため、実装は少なくとも不完全です。

これをよりクリーンな方法で行うことはできますか?

4

2 に答える 2

2

おそらく私は拡張するべきではありませんBufferedReader。私はそれに管理するためのダミーのリーダーを与えることを余儀なくされます、さもなければそれはコンパイルさえしません。[...] read()のような他のメソッドが実際に私のダミーリーダーを参照するため、実装は少なくとも不完全です

read()オーバーライド(および)も可能であり、オーバーライドする必要がありますready()。その実装はreadLine()維持する必要がありますが、少なくとも、すべての読み取り方法が、達成したいインターリーブに準拠していることを確認できます。ダミーリーダーは避けられませんが、実装は避けられます。メモリの浪費を減らすために、BufferedReaderのバッファを可能な限り低い値(1)に設定することもできます。

それ以外は、ストリームのマーキングのサポートを忘れてはなりません。オーバーライドmark()して再実装するか、常にfalseを返すようにreset()オーバーライドする必要があります。markSupported()

于 2012-08-11T15:01:28.360 に答える
1

上記の有用なコメントの後で、私が見つけた解決策を示すために、私は自分の質問に答えています、そしてそれはうまくいくようです。100%正しいかどうかはわかりません(バッファより長い行で何が起こるかはテストされていません)。

最初のバージョンとの違い:

  • Readerではなく、拡張しBufferedReaderます。シンプルで、ダミーのリーダーは必要ありません。その子供たちがいることを確認することによってBufferedReader、それは彼らを呼び出すことができreadLine()ます。
  • それはまだreadLine()私が探していた機能を与えるを実装しています
  • read(char[], int, int)上記を使用して実装されreadLine()ます。そうすれば、線が途切れることはないと確信しています。これは、たとえば、new LineNumberReader(new InterleavedReader(...)).readLine()を呼び出すread(char[], int, int)で必要になりInterleavedReaderます。

これがコードです。改善を提案できるかどうか教えてください!

public class InterleavedReader extends Reader {

    private int current = 0;
    private BufferedReader[] buffers = null;
    private boolean skipLF = false;

    public InterleavedReader(Reader[] in) {
        super();
        buffers = new BufferedReader[in.length];
        for (int i=0 ; i < in.length ; i++) {
            if (in[i] instanceof BufferedReader)
                buffers[i] = (BufferedReader) in[i];
            else
                buffers[i] = new BufferedReader(in[i]);         
        }
    }

    public String readLine() throws IOException {
        // Every time, we issue readLine() to the next child BuffredReader
        // If we make a complete loop without a valid line,
        // then no child has more lines
        synchronized (lock) {
            int start = current;
            String line = null;
            while ((line = buffers[current].readLine()) == null) {
                current = (current+1) % buffers.length;
                if (current == start)
                    return null;
            }       
            current = (current+1) % buffers.length;
            return line;
        }
    }

    @Override
    public int read(char cbuf[], int off, int len) throws IOException {
        // To be sure we never break a line, we implement this using readLine()
        String s = readLine();
        if (s == null)
            return -1;
        System.arraycopy(s.toCharArray(), 0, cbuf, off, s.length());
        // readLine() doesn't include the '\n', append it to the buffer
        cbuf[off+s.length()] = '\n';
        return s.length()+1;
    }


    private int readChar() throws IOException {
        int start = current;
        int c = -1;
        while ((c = buffers[current].read()) == -1) {
            current = (current+1) % buffers.length;
            if (current == start)
                return -1;
        }   
        return c;
    }

    @Override
    public int read() throws IOException {
        synchronized (lock) {
            int c = readChar();
            if (skipLF && c == '\n') {
                c = readChar();
                skipLF = false;
            }
            switch (c) {
            case '\r':
                skipLF = true;
            case '\n':          /* Fall through */
                current = (current+1) % buffers.length;
                return '\n';
            }           
            return c;
        }
    }

    @Override
    public boolean markSupported() {
        return false;
    }

    @Override
    public boolean ready() throws IOException {
        synchronized (lock) {
            for(int i=0; i < buffers.length; i++)
                if (buffers[i].ready())
                    return true;
            return false;
        }
    }

    @Override 
    public void close() throws IOException {
        synchronized (lock) {
            for (int i=0;  i < buffers.length; i++)
                buffers[i].close();
        }
    }
}    
于 2012-08-11T21:04:32.030 に答える