我可以使用 java.nio 作为控制台输入吗?

Can I use java.nio for Console Input?

考虑竞争性编程的场景,我必须从控制台读取 2*10^5(或更多)个数字。然后我使用 BufferedReader 或者为了更快的性能,我使用自定义 reader class,它在后台使用 DataInputStream

快速互联网搜索给了我这个。

We can use java.io for smaller streaming of data and for large streaming we can use java.nio.

所以我想尝试 java.nio 控制台输入并根据 java.io 性能测试它。

  1. 是否可以使用 java.nio 读取控制台输入?
  2. 我可以使用 java.nioSystem.in 读取数据吗?
  3. 它会比我目前使用的输入法更快吗?

任何相关信息将不胜感激。

谢谢✌️

你可以像这样打开一个标准输入通道

FileInputStream stdin = new FileInputStream(FileDescriptor.in);
FileChannel stdinChannel = stdin.getChannel();

当 stdin 被重定向到一个文件时,查询大小、执行快速传输到其他通道甚至内存映射等操作可能会起作用。但是当输入是一个真正的控制台或管道或者你正在读取字符数据时,性能不太可能有显着差异。

性能取决于您阅读它的方式,而不是您使用的class。

直接在通道上操作的代码示例,用于处理白色-space 分隔的十进制数,是

CharsetDecoder cs = Charset.defaultCharset().newDecoder();
ByteBuffer bb = ByteBuffer.allocate(1024);
CharBuffer cb = CharBuffer.allocate(1024);
while(stdinChannel.read(bb) >= 0) {
    bb.flip();
    cs.decode(bb, cb, false);
    bb.compact();
    cb.flip();
    extractDoubles(cb);
    cb.compact();
}
bb.flip();
cs.decode(bb, cb, true);
if(cb.position() > 0) {
    cb.flip();
    extractDoubles(cb);
}
private static void extractDoubles(CharBuffer cb) {
    doubles: for(int p = cb.position(); p < cb.limit(); ) {
        while(p < cb.limit() && Character.isWhitespace(cb.get(p))) p++;
        cb.position(p);
        if(cb.hasRemaining()) {
            for(; p < cb.limit(); p++) {
                if(Character.isWhitespace(cb.get(p))) {
                    int oldLimit = cb.limit();
                    double d = Double.parseDouble(cb.limit(p).toString());
                    cb.limit(oldLimit);
                    processDouble(d);
                    continue doubles;
                }
            }
        }
    }
}

这比使用 java.util.ScannerBufferedReaderreadLine() 后跟 split("\s") 更复杂,但优点是避免了正则表达式引擎的复杂性,以及不为行创建 String 对象。当每行有多个数字或空行时,即行字符串与数字字符串不匹配时,这可以节省字符串构造固有的复制开销。

此代码仍在处理任意字符集。当您知道预期的字符集并且它是基于 ASCII 的时,使用轻量级转换而不是 CharsetDecoder,如 所示,可以获得额外的性能提升。