Могу ли я использовать java .nio для ввода с консоли? - PullRequest
2 голосов
/ 28 мая 2020

Рассмотрим сценарий соревновательного программирования , мне нужно прочитать 2 * 10 ^ 5 (или даже больше) чисел с консоли. Затем я использую BufferedReader или для еще большей производительности я использую собственный класс чтения, который использует DataInputStream под капотом.

Quick Inte rnet поиск дал мне это.

Мы можем использовать java.io для небольших потоков данных, а для больших потоков мы можем использовать java.nio.

Итак, я хочу попробовать ввод консоли java.nio и проверить его на производительность java.io.

  1. Можно ли прочитать ввод консоли с помощью java.nio?
  2. Могу ли я читать данные из System.in, используя java.nio?
  3. Будет ли это быстрее, чем у меня сейчас есть методы ввода?

Мы будем благодарны за любую соответствующую информацию.

Спасибо ✌️

1 Ответ

4 голосов
/ 28 мая 2020

Вы можете открыть канал для stdin, например

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

Когда stdin был перенаправлен в файл, могут работать такие операции, как запрос размера, выполнение быстрой передачи в другие каналы и даже отображение памяти. Но когда вводом является реальная консоль или канал, или вы читаете символьные данные, производительность вряд ли будет значительно отличаться.

Производительность зависит от того, как вы ее читаете, а не от класса, который вы используете.

Пример кода, непосредственно работающего с каналом, для обработки десятичных чисел, разделенных пробелами:

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 s readLine(), за которым следует split("\\s"), но имеет то преимущество, что позволяет избежать сложности механизма регулярных выражений, а также не создавать объекты String для строк. Если в каждой строке или пустых строках более одного числа, то есть строки не будут соответствовать строкам чисел, это может сэкономить накладные расходы на копирование intrinsi c на построение строки.

Этот код все еще обрабатывается произвольные кодировки. Когда вы знаете ожидаемую кодировку и она основана на ASCII, использование облегченного преобразования вместо CharsetDecoder, как показано в , этот ответ может дать дополнительное повышение производительности.

...