Java InputStreamのread(byte[] b)メソッド ありがちなまちがい 2008/01/10
2008/01/20

Javaです。
java.io.InputStreamのありがちなまちがいです。

下記のメソッドbadが悪い理由はわかるでしょうか?
※あまりいい例が浮かばなかった...

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class A {

public static boolean eq(Object o1, Object o2) {
if (o1 != null && o2 != null)
return o1.equals(o2);
return false;
}

public static String randomData(int length, String source) {

StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++) {
builder.append(source.charAt((int) (Math.floor(Math.random()
* source.length()))));

}
return new String(builder);
}


public static void main(String[] args) throws IOException {

String data = randomData(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
System.out.println(eq(data, bad(data)));

data = randomData(256, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
System.out.println(eq(data, bad(data)));

data = randomData(30000, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
System.out.println(eq(data, bad(data)));

data = randomData(10, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
System.out.println(eq(data, good(data)));

data = randomData(256, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
System.out.println(eq(data, good(data)));

data = randomData(30000, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
System.out.println(eq(data, good(data)));

}

/**
* <p>
* このメソッドは正しく文字列読めない.
* </p>
*
* @param data
* @return
* @throws IOException
*/
public static String bad(String data) throws IOException {
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new ByteArrayInputStream(data
.getBytes()));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bs = new byte[256];
while (bis.read(bs) != -1) {
baos.write(bs);
}

return new String(baos.toByteArray());
} finally {
if (bis != null) {
bis.close();
}
}

}

/**
* <p>このメソッドはまずくない。</p>
* @param data
* @return
* @throws IOException
*/
public static String good(String data) throws IOException {
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new ByteArrayInputStream(data
.getBytes()));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bs = new byte[256];
int size = 0;
while ((size = bis.read(bs)) != -1) {
baos.write(bs, 0, size);
}

return new String(baos.toByteArray());
} finally {
if (bis != null) {
bis.close();
}
}

}

}


結果は、
false
true
false
true
true
true
となります。

ありがちなのは、InputStreamのread(byte[] b)メソッドに渡すバッファの値が読み込まれるたびにクリアになって、読みこんだサイズ分しかバイトの配列ができないと思い込んでしまうことかなと。
(冷静になって考えれば、配列オブジェクトを渡しているのだからのその長さは変えられないことに気がつきそうですが...あせっていると...)

Javadocにはこう書かれています。
最初に読み込まれたバイトは要素 b[0] に格納され、次のバイトは b[1] に格納されます。読み込まれるバイト数の上限は、b の長さと同じです。ここで、k を実際に読み込まれたバイト数とします。読み込まれたバイトは、要素 b[0] 〜 b[k-1] に格納され、要素 b[k] 〜 b[b.length-1] は影響を受けません。JavaTM 2 Platform Standard Ed. 5.0


なので、ファイル読み込むメソッドで使用したりしてデータが壊れてみえてしまうということがおこるわけですね。


参考
指定した文字を使って、ランダムな文字列を作成する - Enjoy*Study

:

匿名

test コメント