Как записать стандартный ввод (более одной строки) в строку в Dart?

У меня есть программа командной строки Dart, которая хочет иметь возможность передавать данные из оболочки в программу Dart (например, cat file.txt | dart my_program.dart или принимать ввод, пока пользователь не нажмет Ctrl+d). Просматривая учебные пособия в Интернете, единственная документация, которую я нашел при сохранении ввода из стандартного ввода, была stdin.readLineSync(). Однако, как следует из названия, это читает только первую строку.

Как записать все содержимое стандартного ввода в строку? Кроме того, возникнут ли какие-либо проблемы с безопасностью, если пользователь попытается передать чрезвычайно большой файл? Есть ли ограничение на длину строки? Как я могу защититься от этого?

Спасибо за вашу помощь!


person Dariel Dato-on    schedule 01.03.2015    source источник


Ответы (3)


Следующая программа, если она используется в интерактивном режиме, будет повторять ваш ввод, но использовать заглавные буквы для каждого символа.

Вы также можете подключить к нему файл.

dart upper_cat.dart < file.txt

Это выведет файл с заглавными буквами каждого символа.

import 'dart:convert';
import 'dart:io';

main() {

  // Stop your keystrokes being printed automatically.
  stdin.echoMode = false;

  // This will cause the stdin stream to provide the input as soon as it
  // arrives, so in interactive mode this will be one key press at a time.
  stdin.lineMode = false;

  var subscription;
  subscription = stdin.listen((List<int> data) {

    // Ctrl-D in the terminal sends an ascii end of transmission character.
    // http://www.asciitable.com/
    if (data.contains(4)) {
      // On my computer (linux) if you don't switch this back on the console
      // will do wierd things.
      stdin.echoMode = true;

      // Stop listening.
      subscription.cancel();
    } else {

      // Translate character codes into a string.
      var s = LATIN1.decode(data);

      // Capitalise the input and write it back to the screen.
      stdout.write(s.toUpperCase());
    }
  });

}

Существует также библиотека console, помогающая с такими вещами. Я не пробовал, но попробую и отчитаюсь ;)

В следующем примере обрабатывается ввод UTF8 — в приведенном выше примере в качестве входных данных требуются 1-байтовые символы.

import 'dart:convert';
import 'dart:io';

main() {

  stdin.echoMode = false;
  stdin.lineMode = false;

  var subscription;
  subscription = stdin
    .map((List<int> data) {
      if (data.contains(4)) {
        stdin.echoMode = true;
        subscription.cancel();
      }
      return data;
    })
    .transform(UTF8.decoder)
    .map((String s) => s.toUpperCase())
    .listen(stdout.write);
}
person Greg Lowe    schedule 02.03.2015
comment
Привет, Грег! Спасибо за ваше предложение. Я не мог понять, как изменить ваш код, чтобы он соответствовал моим потребностям. Смотрите мой комментарий к решению Гюнтера. По сути, я пытаюсь сделать что-то вроде String input = stdin.readLineSync(), но иметь возможность сохранять несколько строк вместо одной. Если у вас есть другие предложения, пожалуйста, дайте мне знать! Спасибо! - person Dariel Dato-on; 12.03.2015
comment
Я думаю, вам нужно более четко определить проблему, которую вы пытаетесь решить. т. е. функция может прослушивать ввод и возвращать строку, когда поступает Ctrl+D. Или программа может дождаться символа новой строки и вернуть строку, содержащую строку. Если программа должна прочитать несколько строк, как она узнает, что чтение завершено? Будет ли он ждать, пока не прочитает пустую строку? Или будет ждать, пока не прочитает строку с окончанием слова? - person Greg Lowe; 12.03.2015

Я изучил код stdin.readLineSync() и смог модифицировать его под свои нужды:

import 'dart:convert';
import 'dart:io';

String readInputSync({Encoding encoding: SYSTEM_ENCODING}) {
  final List input = [];
  while (true) {
    int byte = stdin.readByteSync();
    if (byte < 0) {
      if (input.isEmpty) return null;
      break;
    }
    input.add(byte);
  }
  return encoding.decode(input);
}

void main() {
  String input = readInputSync();
  myFunction(input); // Take the input as an argument to a function
}

Мне нужно было синхронно читать со стандартного ввода, чтобы приостановить программу до тех пор, пока не будет прочитан весь стандартный ввод (до конца файла или Ctrl+d).

Спасибо за вашу помощь! Думаю, без вашей помощи я бы не разобрался.

person Dariel Dato-on    schedule 13.03.2015

Вы можете использовать

import 'dart:io' as io;
import 'dart:async' show Future, Stream, StreamSubscription;
import 'dart:convert' show UTF8;

void main() {
  StreamSubscription subscr = io.stdin.transform(UTF8.decoder).listen((data) => 
      print(data));
}

Вы можете контролировать, следует ли получать больше данных или нет, с помощью

subscr.pause();
subscr.resume();

Прослушивание стандартного ввода передает данные порциями по 16 КБ, если я правильно помню (размер буфера ввода-вывода определяется Dart), это позволяет вам получать объем данных, который вы можете обработать. Если вы хотите сохранить одну большую строку в памяти, вам нужно иметь эту память.

См. также
- https://stackoverflow.com/a/26343041/217408 (настройка памяти ВМ)
- https://stackoverflow.com/a/12691502/217408
- https://stackoverflow.com/a/28039661/217408

person Günter Zöchbauer    schedule 01.03.2015
comment
Спасибо, Гюнтер. Я попробовал ваше предложение, но я до сих пор не уверен, как это может захватить стандартный ввод в строку в Dart. Можете ли вы немного расширить свой ответ? Спасибо еще раз! - person Dariel Dato-on; 02.03.2015
comment
Я обновил свой ответ. Если вам нужен более конкретный ответ, пожалуйста, предоставьте больше информации о том, что вы пытаетесь выполнить и что именно вызывает у вас проблемы. - person Günter Zöchbauer; 02.03.2015
comment
Эй, Гюнтер. Извините, что поздно возвращаюсь к вам по этому поводу. Ваше предложение работает, но я не смог изменить его в соответствии со своими потребностями. По сути, я пытаюсь сделать что-то вроде String input = stdin.readLineSync(), но иметь возможность сохранять несколько строк вместо одной. Для фона я работаю над препроцессором CSS. Поэтому мне нужно сохранить стандартный ввод в строку, а затем обработать строку. - person Dariel Dato-on; 12.03.2015