【问题标题】:Read all standard input into a Java byte array将所有标准输入读入 Java 字节数组
【发布时间】:2013-09-21 18:38:25
【问题描述】:

在现代 Java 中(仅使用标准库)读取 所有 标准输入直到 EOF 进入字节数组的最简单方法是什么,最好不必自己提供该数组?标准输入数据是二进制数据,并非来自文件。

即类似于 Ruby 的

foo = $stdin.read

我能想到的唯一部分解决方案是

byte[] buf = new byte[1000000];
int b;
int i = 0;

while (true) {
    b = System.in.read();
    if (b == -1)
        break;
    buf[i++] = (byte) b;
}

byte[] foo[i] = Arrays.copyOfRange(buf, 0, i);

...但即使对于 Java 来说,这也显得异常冗长,并且使用固定大小的缓冲区。

【问题讨论】:

    标签: java unix stdin


    【解决方案1】:

    我会使用Guava 及其ByteStreams.toByteArray 方法:

    byte[] data = ByteStreams.toByteArray(System.in);
    

    不使用任何 3rd 方库,我会使用 ByteArrayOutputStream 和临时缓冲区:

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[32 * 1024];
    
    int bytesRead;
    while ((bytesRead = System.in.read(buffer)) > 0) {
        baos.write(buffer, 0, bytesRead);
    }
    byte[] bytes = baos.toByteArray();
    

    ...可能将其封装在一个接受InputStream的方法中,无论如何这基本上等同于ByteStreams.toByteArray...

    【讨论】:

    • 谢谢。非常疯狂的是,像 Guava 解决方案这样的东西不在主线标准库中。
    • 它不是的原因是因为 Java 作者试图阻止将内容读入字节数组(这将破坏足够大的数据),而它可以/应该作为流处理(可以处理无限数据量)。
    【解决方案2】:

    如果您正在读取文件,Files.readAllBytes 是这样做的方式。

    否则,我会使用 ByteBuffer:

    ByteBuffer buf = ByteBuffer.allocate(1000000);
    ReadableByteChannel channel = Channels.newChannel(System.in);
    while (channel.read(buf) >= 0)
        ;
    buf.flip();
    byte[] bytes = Arrays.copyOf(buf.array(), buf.limit());
    

    【讨论】:

    • 这是错误的,因为您没有检查 buf.hasRemaining()
    • 实际上,检查 hasRemaining() 是个坏主意。目标是读取所有字节,所以我们不想仅仅因为我们到达缓冲区的末尾而默默地停止读取。例外比将截断的数据视为完整数据更好。我假设最大大小为 1000000,因为 OP 似乎对这个假设很满意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多