0

私は以下を使用してファイルからバイトを読み取っています:

FileSystem fs = config.getHDFS();
            try {

                Path path = new Path(dirName + '/' + fileName);

                byte[] bytes = new byte[(int)fs.getFileStatus(path)
                        .getLen()];
                in = fs.open(path);

                in.read(bytes);
                result = new DataInputStream(new ByteArrayInputStream(bytes));
            } catch (Exception e) {
                e.printStackTrace();
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }

私が読んでいるディレクトリには約15,000個のファイルがあります。ある時点の後、in.read(bytes)の行でこの例外が発生します:

2012-05-31 14:11:45,477 [INFO:main] (DFSInputStream.java:414) - Failed to connect to /165.36.80.28:50010, add to deadNodes and continue
java.io.EOFException
        at java.io.DataInputStream.readShort(DataInputStream.java:298)
        at org.apache.hadoop.hdfs.protocol.DataTransferProtocol$Status.read(DataTransferProtocol.java:115)
        at org.apache.hadoop.hdfs.BlockReader.newBlockReader(BlockReader.java:427)
        at org.apache.hadoop.hdfs.DFSInputStream.getBlockReader(DFSInputStream.java:725)
        at org.apache.hadoop.hdfs.DFSInputStream.blockSeekTo(DFSInputStream.java:390)
        at org.apache.hadoop.hdfs.DFSInputStream.read(DFSInputStream.java:514)
        at java.io.DataInputStream.read(DataInputStream.java:83)

スローされる別の例外は次のとおりです。

2012-05-31 15:09:14,849 [INFO:main] (DFSInputStream.java:414) - Failed to connect to /165.36.80.28:50010, add to deadNodes and continue
java.net.SocketException: No buffer space available (maximum connections reached?): connect
    at sun.nio.ch.Net.connect(Native Method)
    at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:507)
    at org.apache.hadoop.net.SocketIOWithTimeout.connect(SocketIOWithTimeout.java:192)
    at org.apache.hadoop.net.NetUtils.connect(NetUtils.java:373)
    at org.apache.hadoop.hdfs.DFSInputStream.getBlockReader(DFSInputStream.java:719)
    at org.apache.hadoop.hdfs.DFSInputStream.blockSeekTo(DFSInputStream.java:390)
    at org.apache.hadoop.hdfs.DFSInputStream.read(DFSInputStream.java:514)
    at java.io.DataInputStream.read(DataInputStream.java:83)

何が問題になるのかアドバイスしてください。

4

1 に答える 1

3

からの戻り値を無視しておりin.read、ファイル全体を一度に読み取ることができると想定しています。そうしないでください。-1 が返されるか、必要なだけのデータを読み取るまでループreadします。このように本当に信頼する必要があるかどうかは、私には明らかではありませんgetLen().2つの呼び出しの間にファイルが拡大(または縮小)するとどうなりますか?

ByteArrayOutputStream書き込み先と小さい (16K?) バッファーを一時ストレージとして作成し、ループ ラウンド - バッファーに読み取り、そのバイト数を出力ストリームに書き込み、泡立て、すすぎ、 read-1 が返されるまで繰り返すことをお勧めします。ストリームの終わり。次に、からデータを取得しByteArrayOutputStreamて、以前と同じように に入れることができますByteArrayInputStream

編集:テストされていないクイックコード-同様の(より良い)コードがGuavaにあります。

public static byte[] readFully(InputStream stream) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[16 * 1024];
    int bytesRead;
    while ((bytesRead = stream.read(buffer)) > 0) {
        baos.write(buffer, 0, bytesRead);
    }
    return baos.toByteArray();
}

次に、次を使用します。

in = fs.open(path);
byte[] data = readFully(in);
result = new DataInputStream(new ByteArrayInputStream(data));

finallyまた、例外だけでなく、ブロックでストリームを閉じる必要があることに注意してください。また、自分自身を捕まえないようにアドバイスしExceptionます。

于 2012-05-31T19:11:43.303 に答える