我可以使用 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
性能测试它。
- 是否可以使用
java.nio
读取控制台输入?
- 我可以使用
java.nio
从 System.in
读取数据吗?
- 它会比我目前使用的输入法更快吗?
任何相关信息将不胜感激。
谢谢✌️
你可以像这样打开一个标准输入通道
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.Scanner
或 BufferedReader
的 readLine()
后跟 split("\s")
更复杂,但优点是避免了正则表达式引擎的复杂性,以及不为行创建 String
对象。当每行有多个数字或空行时,即行字符串与数字字符串不匹配时,这可以节省字符串构造固有的复制开销。
此代码仍在处理任意字符集。当您知道预期的字符集并且它是基于 ASCII 的时,使用轻量级转换而不是 CharsetDecoder
,如 所示,可以获得额外的性能提升。
考虑竞争性编程的场景,我必须从控制台读取 2*10^5(或更多)个数字。然后我使用 BufferedReader
或者为了更快的性能,我使用自定义 reader class,它在后台使用 DataInputStream
。
快速互联网搜索给了我这个。
We can use
java.io
for smaller streaming of data and for large streaming we can usejava.nio
.
所以我想尝试 java.nio
控制台输入并根据 java.io
性能测试它。
- 是否可以使用
java.nio
读取控制台输入? - 我可以使用
java.nio
从System.in
读取数据吗? - 它会比我目前使用的输入法更快吗?
任何相关信息将不胜感激。
谢谢✌️
你可以像这样打开一个标准输入通道
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.Scanner
或 BufferedReader
的 readLine()
后跟 split("\s")
更复杂,但优点是避免了正则表达式引擎的复杂性,以及不为行创建 String
对象。当每行有多个数字或空行时,即行字符串与数字字符串不匹配时,这可以节省字符串构造固有的复制开销。
此代码仍在处理任意字符集。当您知道预期的字符集并且它是基于 ASCII 的时,使用轻量级转换而不是 CharsetDecoder
,如