The next JAVA library(9)

ByteArrayInputStreamと、ByteArrayOutputStreamですが、両方ともbyte配列に対して処理を行います。
byte配列なのだから、readとwriteを同時に出来ても良いような気がします。
つまり、次のように使用すればいいのです。

ByteArrayOutputStream baos = new ByteArrayOutputStream(fileSize);
byte[] stream = baos.toByteArray();
InputStream is = getClass().getResourceAsStream(fileName);
is.read(stream);
is.close();
ByteArrayInputStream bais = new ByteArrayInputStream(stream);

まずByteArrayOutputStreamに、ファイルサイズ分のbyte配列を内部に作成させて、そのbyte配列を取得します。
次に、そのbyte配列に、InputStreamからのデータを入れてやります。
で、最後に、ByteArrayInputStreamにそれを関連付けてやれば、同じbyte配列を扱うことが出来るようになるはずです。
ちょっと実験してみます。

if(stream.length == fileSize){
    System.out.println("一致");
}else{
    System.out.println("不一致");
}

で、これを実行してみると、
不一致でしたorz
stream.lengthを出力してみると、この値が0になってました(;´Д`)
いや、確かに、ByteArrayOutputStreamは、内部的に自由に伸張が出来るようになってるみたいだけど、それならコンストラクタでサイズを指定出来るのって何?
このサイズ以上に書き込もうとすれば例外が発生するようになってるのかな、と思って、

baos.write(new byte[fileSize]);
System.out.println("length1:"+baos.toByteArray().length);
baos.write(1);
System.out.println("length2:"+baos.toByteArray().length);

こんな感じのプログラムを書いてみたけど、length1では、fileSizeが返ってきて、length2では、fileSize+1が正常に返ってきました。
何これ(;´Д`)
ちょっと凹みましたよ。いやまじで。
ByteArrayOutputStreamの内部的なbyte配列を、こちらから操作出来ないのであれば、readとwriteを同時に行うことなんか出来やしません。
∩(・∀・)∩ モウ オテアゲダネ


と思ってたのですが、よく考えてみると、別に無理してByteArrayInputStreamやByteArrayOutputStreamを使用する必要なんか無かったんですよね。
内部的にbyte配列とオフセットさえ持てばいいのだから、簡単に実装出来ます。
open()は機種依存になるので後回しにするとして、とりあえずread()とwrite()は次のようになりますね。

protected byte stream;
protected int streamOffset;

protected int _read(byte buf, int off, int len){
    if(streamOffset >= stream.length) return -1;
    if(len > stream.length - streamOffset)
        len = stream.length - streamOffset;
    System.arraycopy(stream, streamOffset, buf, off, len);
    streamOffset += len;
    return len;
}

protected void _write(byte[] buf, int off, int len){
    try{
        if(streamOffset >= stream.length)
            throw new EOFException("end of file");
        if(len > stream.length - streamOffset)
            throw new IOException("length doesn't suffice");
    }catch(Exception e){
        System.out.println("write:"+e);
    }
    System.arraycopy(buf, off, stream, streamOffset, len);
    streamOffset += len;
    bWrite = true;
}

非常に短くなりましたヽ(´ー`)ノ
例外を発生させてるくせに、すぐにcatchしてるのは、メイン側で例外をcatchするのが面倒だからです(ぉ
その辺は自分の趣味なので気にしないでくださいw


で、あとはreadInt()や、1バイト読み込みのread()ですが、byteToInt()とintToByte()を用意しておけば、あとはread(byte[],int,int)に委譲するだけで、簡単に実装することが出来ます。

//byteをintに変換(big endian)
//len-offが4以上だった場合は(´ー`)チラネーヨ
static public int byteToInt(byte b, int off, int len){
    int ret = 0;
    for(int i=off;i<off+len;i++){
        ret |= ((b[i] & 0xff) << ((off+len-i-1)*8));
    }
    return ret;
}

//intをbyteに変換
static public byte intToByte(int n){
    byte b = new byte[4];
    b[0] = (byte)((n>>24)&0xff);
    b[1] = (byte)((n>>16)&0xff);
    b[2] = (byte)((n>>8 )&0xff);
    b[3] = (byte)((n    )&0xff);
    return b;
}

private byte b4 = new byte[4];

protected int _read(){
    int n = _read(b4, 0, 1);
    if(n == 1) return b4[0];
    else return -1;
}

protected int _readInt(){
    int n = _read(b4, 0, 4);
    try{
        if(n != 4) throw new EOFException("end of file");
    }catch(Exception e){
        System.out.println("readInt:"+e);
    }
    return byteToInt(b4, 0, 4);
}

protected void _write(int b){
    b4[0] = (byte)(b&0xff);
    _write(b4, 0, 1);
}

protected void _writeInt(int v){
    _write(intToByte(v), 0, 4);
}

あとは、seekメソッドも欲しいところですね。

protected void _seek(int s){
    try{
        if(s<0 || s>=stream.length)
            throw new IOException("seek out of bounds");
    }catch(Exception e){
        System.out.println("seek:"+e);
    }
    streamOffset = s;
}

これだけあれば、ファイル操作は簡単にできるでしょう。
これで大体出来上がりです。
あとはDoCoMoMIDPに分けて、byte配列を取得するopen()メソッドと、編集したbyte配列を出力するclose()メソッドを書けば完成です。


ということで続きはまた明日(ぉ