IO
Функции обработки ввода-вывода (IO).
Многие функции в этом модуле ожидают устройство ввода-вывода в качестве аргумента. Устройство ввода-вывода должно быть PID или атомом, представляющим процесс. Для удобства Elixir предоставляет :stdio и :stderr в качестве сокращений для :standard_io и :standard_error Erlang.
Большинство функций ожидают chardata. В случае, если передается другой тип, функции преобразуют эти типы в строку с помощью протокола String.Chars (как показано в спецификациях типов). Более подробную информацию о chardata см. в разделе "Данные IO" ниже.
Устройства ввода-вывода
Устройство ввода-вывода может быть атомом или PID. В случае атома, атом должен быть именем зарегистрированного процесса. Кроме того, Elixir предоставляет два сокращения:
-
:stdio- сокращение для:standard_io, которое отображается на текущийProcess.group_leader/0в Erlang -
:stderr- сокращение для именованного процесса:standard_error, предоставленного в Erlang
Устройства ввода-вывода сохраняют свою позицию, что означает, что последующие вызовы функций чтения или записи будут начинаться с места, где устройство было в последний раз обработано. Позицию файлов можно изменить с помощью функции :file.position/2.
Данные IO
Данные IO — это тип данных, который может использоваться в качестве более эффективной альтернативы бинарным данным в определенных ситуациях.
Значение типа Данные IO — это бинарный массив или список, содержащий байты (целые числа в 0..255) или вложенные данные IO. Тип рекурсивный. Посмотрим пример одного из возможных представлений бинарных данных "hello":
[?h, "el", ["l", [?o]]]
Встроенный тип iodata/0 определен в терминах iolist/0. Список IO такой же, как данные IO, но не допускает бинарных данных на верхнем уровне (но бинарные данные все еще разрешены в самом списке).
Примеры использования данных IO
Данные IO существуют, потому что часто требуется выполнить много операций добавления к меньшим частям бинарных данных для создания большего бинарного массива. Однако в Erlang и Elixir конкатенация бинарных данных копирует конкатенированные бинарные данные в новый бинарный массив.
def email(username, domain) do username <> "@" <> domain end
В этой функции создание адреса электронной почты скопирует бинарные данные username и domain. Теперь представьте, что вы хотите использовать полученный адрес электронной почты внутри другого бинарного массива:
def welcome_message(name, username, domain) do
"Welcome #{name}, your email is: #{email(username, domain)}"
end
IO.puts(welcome_message("Meg", "meg", "example.com"))
#=> "Welcome Meg, your email is: meg@example.com" Каждый раз, когда вы конкатенируете бинарные данные или используете интерполяцию (#{}), вы создаете копии этих бинарных данных. Однако во многих случаях вам не нужен весь бинарный массив во время его создания, а только в конце, чтобы напечатать его или отправить куда-либо. В таких случаях вы можете построить бинарный массив, создав данные IO:
def email(username, domain) do
[username, ?@, domain]
end
def welcome_message(name, username, domain) do
["Welcome ", name, ", your email is: ", email(username, domain)]
end
IO.puts(welcome_message("Meg", "meg", "example.com"))
#=> "Welcome Meg, your email is: meg@example.com" Создание данных IO дешевле, чем конкатенация бинарных данных. Конкатенация нескольких частей данных IO просто означает объединение их в список, так как данные IO могут быть произвольно вложены, а это недорогая и эффективная операция. Большинство API на основе IO, таких как :gen_tcp, IO и т. д., принимают данные IO и записывают их в сокет напрямую без преобразования в бинарный массив.
Один из недостатков данных IO заключается в том, что вы не можете выполнять такие действия, как сопоставление шаблонов с первой частью данных IO, как с бинарными данными, потому что вы обычно не знаете структуру данных IO. В таких случаях вам может потребоваться преобразовать их в бинарный массив, вызвав iodata_to_binary/1, что достаточно эффективно, так как реализовано нативно на C. Другие функции, такие как вычисление длины данных IO, могут быть вычислены непосредственно на данных IO, вызвав iodata_length/1.
Chardata
Erlang и Elixir также имеют понятие chardata/0. Chardata очень похожи на данные IO: единственное различие состоит в том, что целые числа в данных IO представляют байты, а целые числа в chardata представляют кодовые точки Юникода. Байты (byte/0) — это целые числа в диапазоне 0..255, а кодовые точки Юникода (char/0) — целые числа в диапазоне 0..0x10FFFF. Модуль IO предоставляет функцию chardata_to_string/1 для chardata в качестве "аналога" функции iodata_to_binary/1 для данных IO.
Если вы попытаетесь использовать iodata_to_binary/1 для chardata, это приведет к ошибке аргумента. Например, давайте попробуем поместить кодовую точку, которую нельзя представить одним байтом, например, ?π, внутри данных IO:
iex> IO.iodata_to_binary(["The symbol for pi is: ", ?π]) ** (ArgumentError) argument error
Если мы используем chardata вместо этого, это будет работать как ожидается:
iex> IO.chardata_to_string(["The symbol for pi is: ", ?π]) "The symbol for pi is: π"
Сводка
Типы
Функции
- binread(device \\ :stdio, line_or_chars)
Читает из устройства IO
device. Операция небезопасна для Юникода.- binstream(device, line_or_bytes)
Преобразует устройство ввода-вывода IO
deviceвIO.Stream. Операция небезопасна для Юникода.- binwrite(device \\ :stdio, iodata)
Записывает
iodataв указанное устройствоdevice.- chardata_to_string(string)
Преобразует chardata в строку.
- getn(prompt, count \\ 1)
Получает количество байтов из устройства ввода-вывода IO
:stdio.- getn(device, prompt, count)
Получает количество байтов из устройства IO
device.- gets(device \\ :stdio, prompt)
Считывает строку из устройства IO
device.- inspect(item, opts \\ [])
Отображает и записывает данное
itemв устройство.- inspect(device, item, opts)
Отображает
itemв соответствии с заданными параметрами с помощью устройства ввода-вывода IOdevice.- iodata_length(iodata)
Возвращает размер данных IO.
- iodata_to_binary(iodata)
Преобразует данные IO в бинарный массив
- puts(device \\ :stdio, item)
Записывает
itemв указанное устройствоdevice, аналогичноwrite/2, но добавляет символ новой строки в конце.- read(device \\ :stdio, line_or_chars)
Читает из устройства IO
device.- stream(device, line_or_codepoints)
Преобразует устройство IO
deviceвIO.Stream.- warn(message)
Записывает
messageв stderr вместе со текущим стеком вызовов.- warn(message, stacktrace)
Записывает
messageв stderr вместе с указаннымstacktrace.- write(device \\ :stdio, chardata)
Записывает
chardataв указанное устройствоdevice.
Типы
chardata()
Specs
chardata() :: String.t() | maybe_improper_list(char() | chardata(), String.t() | [])
device()
Specs
device() :: atom() | pid()
nodata()
Specs
nodata() :: {:error, term()} | :eof Функции
binread(device \\ :stdio, line_or_chars)
Характеристики
binread(device(), :all | :line | non_neg_integer()) :: iodata() | nodata()
Считывает данные из Ввода-Вывода device. Операция не безопасна для Unicode.
device итерируется заданным количеством байтов или построчно, если задано :line. В альтернативном случае, если задано :all, возвращается весь device.
Возвращает:
-
data- выходные байты -
:eof- достигнут конец файла -
{:error, reason}- другая (редкая) ошибка; например,{:error, :estale}при чтении с NFS-тома
Если задано :all, :eof никогда не возвращается, а возвращается пустая строка в случае достижения EOF устройством.
Примечание: не используйте эту функцию с устройствами Ввода-Вывода в режиме Unicode, так как она вернёт неверный результат.
binstream(device, line_or_bytes)
Характеристики
binstream(device(), :line | pos_integer()) :: Enumerable.t()
Преобразует Ввод-Вывод device в IO.Stream. Операция не безопасна для Unicode.
IO.Stream реализует как Enumerable, так и Collectable, что позволяет использовать его для чтения и записи.
device итерируется заданным количеством байтов или построчно, если задано :line. Это считывает данные с устройства Ввода-Вывода как сырой двоичный поток.
Обратите внимание, что поток Ввода-Вывода имеет побочные эффекты, и каждый раз при проходе через поток вы можете получить разные результаты.
Наконец, не используйте эту функцию с устройствами Ввода-Вывода в режиме Unicode, так как она вернёт неверный результат.
binwrite(device \\ :stdio, iodata)
Характеристики
binwrite(device(), iodata()) :: :ok | {:error, term()} Записывает iodata на заданный device.
Данная операция предназначена для использования с "сырыми" устройствами, которые запускаются без кодировки. Заданные iodata записываются на устройство без преобразования. Дополнительную информацию о данных Ввода-Вывода см. в разделе "Данные Ввода-Вывода" в документации модуля.
Используйте write/2 для устройств с кодировкой.
Важно: не используйте эту функцию с устройствами Ввода-Вывода в режиме Unicode, так как она запишет неверные данные. В частности, стандартное устройство Ввода-Вывода по умолчанию настроено на режим Unicode, поэтому запись в stdio с помощью этой функции, вероятно, приведёт к отправке неверных данных.
chardata_to_string(string)
Характеристики
chardata_to_string(chardata()) :: String.t()
Преобразует chardata в строку.
Для получения дополнительной информации о chardata см. раздел ""Chardata"" в документации модуля.
В случае неудачи преобразования генерируется исключение UnicodeConversionError. Если задана строка, возвращается сама строка.
Примеры
iex> IO.chardata_to_string([0x00E6, 0x00DF])
"æß"
iex> IO.chardata_to_string([0x0061, "bc"])
"abc"
iex> IO.chardata_to_string("string")
"string" getn(prompt, count \\ 1)
Характеристики
getn(chardata() | String.Chars.t(), pos_integer()) :: chardata() | nodata()
getn(device(), chardata() | String.Chars.t()) :: chardata() | nodata()
Считывает заданное количество байтов с устройства Ввода-Вывода :stdio.
Если :stdio является устройством Unicode, count предполагает количество точек кода Unicode для извлечения. В противном случае count представляет количество считываемых байтов.
См. IO.getn/3 для описания значений возврата.
getn(device, prompt, count)
Характеристики
getn(device(), chardata() | String.Chars.t(), pos_integer()) :: chardata() | nodata()
Считывает заданное количество байтов с устройства Ввода-Вывода device.
Если устройство Ввода-Вывода device является устройством Unicode, count предполагает количество точек кода Unicode для извлечения. В противном случае count представляет количество считываемых байтов.
Возвращает:
-
data- введённые символы -
:eof- достигнут конец файла -
{:error, reason}- другая (редкая) ошибка; например,{:error, :estale}при чтении с NFS-тома
gets(device \\ :stdio, prompt)
Характеристики
gets(device(), chardata() | String.Chars.t()) :: chardata() | nodata()
Считывает строку с устройства Ввода-Вывода device.
Возвращает:
-
data- символы в строке, завершённые символом новой строки (LF) или концом файла (EOF) -
:eof- достигнут конец файла -
{:error, reason}- другая (редкая) ошибка; например,{:error, :estale}при чтении с NFS-тома
Примеры
Чтобы отобразить "Как вас зовут?" в качестве подсказки и дождаться ввода пользователя:
IO.gets("What is your name?\n") inspect(item, opts \\ [])
Характеристики
inspect(item, keyword()) :: item when item: var
Проверяет и записывает заданный item на устройство.
Важно отметить, что она возвращает заданный item без изменений. Это позволяет "просматривать" значения, вставляя вызов IO.inspect/2 практически в любом месте вашего кода, например, в середине конвейера.
По умолчанию она включает красивую печать с шириной 80 символов. Ширину можно изменить, явно передав параметр :width.
Вывод может быть помечен меткой, передав параметр :label, чтобы легко отличить его от других вызовов IO.inspect/2. Метка будет выведена перед проверяемым item.
См. Inspect.Opts для полного списка дополнительных параметров форматирования.
Примеры
IO.inspect(<<0, 1, 2>>, width: 40)
Выводит:
<<0, 1, 2>>
Можно использовать опцию :label для маркирования вывода:
IO.inspect(1..100, label: "a wonderful range")
Выводит:
a wonderful range: 1..100
Опция :label особенно полезна в конвейерах:
[1, 2, 3] |> IO.inspect(label: "before") |> Enum.map(&(&1 * 2)) |> IO.inspect(label: "after") |> Enum.sum()
Выводит:
before: [1, 2, 3] after: [2, 4, 6]
inspect(device, item, opts)
Характеристики
inspect(device(), item, keyword()) :: item when item: var
Проверяет item в соответствии с заданными параметрами с помощью устройства Ввода-Вывода device.
См. inspect/2 для полного списка параметров.
iodata_length(iodata)
Характеристики
iodata_length(iodata()) :: non_neg_integer()
Возвращает размер данных Ввода-Вывода.
Для получения дополнительной информации о данных Ввода-Вывода см. раздел "Данные Ввода-Вывода" в документации модуля.
Встроено компилятором.
Примеры
iex> IO.iodata_length([1, 2 | <<3, 4>>]) 4
iodata_to_binary(iodata)
Характеристики
iodata_to_binary(iodata()) :: binary()
Преобразует данные Ввода-Вывода в двоичный формат.
Операция не безопасна для Unicode.
Обратите внимание, что эта функция обрабатывает целые числа в заданных данных Ввода-Вывода как сырые байты и не выполняет никаких преобразований кодировки. Если вы хотите преобразовать список символов в строку с UTF-8 кодировкой, используйте chardata_to_string/1. Дополнительную информацию о данных Ввода-Вывода и chardata см. в разделе "Данные Ввода-Вывода" в документации модуля.
Если эта функция получает двоичные данные, возвращаются те же двоичные данные.
Встроено компилятором.
Примеры
iex> bin1 = <<1, 2, 3>> iex> bin2 = <<4, 5>> iex> bin3 = <<6>> iex> IO.iodata_to_binary([bin1, 1, [2, 3, bin2], 4 | bin3]) <<1, 2, 3, 1, 2, 3, 4, 5, 4, 6>> iex> bin = <<1, 2, 3>> iex> IO.iodata_to_binary(bin) <<1, 2, 3>>
puts(device \\ :stdio, item)
Характеристики
puts(device(), chardata() | String.Chars.t()) :: :ok
Записывает item на заданное device, аналогично write/2, но добавляет символ новой строки в конце.
По умолчанию device - стандартный вывод. Возвращает :ok в случае успеха.
Примеры
IO.puts("Hello World!")
#=> Hello World!
IO.puts(:stderr, "error")
#=> error read(device \\ :stdio, line_or_chars)
Характеристики
read(device(), :all | :line | non_neg_integer()) :: chardata() | nodata()
Считывает данные с устройства Ввода-Вывода device.
device итерируется заданным количеством символов или построчно, если задано :line. В альтернативном случае, если задано :all, возвращается весь device.
Возвращает:
-
data- выходные символы -
:eof- достигнут конец файла -
{:error, reason}- другая (редкая) ошибка; например,{:error, :estale}при чтении с NFS-тома
Если задано :all, :eof никогда не возвращается, а возвращается пустая строка в случае достижения EOF устройством.
stream(device, line_or_codepoints)
Характеристики
stream(device(), :line | pos_integer()) :: Enumerable.t()
Преобразует ввод/вывод device в IO.Stream.
IO.Stream реализует как Enumerable, так и Collectable, позволяя использовать его для чтения и записи.
device итерируется заданным количеством символов или по строкам, если указано :line.
Чтение выполняется в формате UTF-8. Обратитесь к IO.binstream/2 для обработки ввода/вывода как сырого двоичного.
Обратите внимание, что потоки ввода/вывода имеют побочные эффекты, и каждый раз при обращении к потоку вы можете получить разные результаты.
Примеры
Вот пример эмуляции эхо-сервера из командной строки:
Enum.each(IO.stream(:stdio, :line), &IO.write(&1))
warn(message)
Характеристики
warn(chardata() | String.Chars.t()) :: :ok
Выводит message в stderr вместе со текущим трассировкой стека.
Возвращает :ok в случае успеха.
Примеры
IO.warn("variable bar is unused")
#=> warning: variable bar is unused
#=> (iex) evaluator.ex:108: IEx.Evaluator.eval/4 warn(message, stacktrace)
Характеристики
warn(chardata() | String.Chars.t(), Exception.stacktrace()) :: :ok
Выводит message в stderr вместе с заданной stacktrace.
Эта функция также сообщает компилятору о выводе предупреждения (в случае включения --warnings-as-errors). Возвращает :ok в случае успеха.
Для предотвращения вывода трассировки стека можно передать пустой список.
Примеры
stacktrace = [{MyApp, :main, 1, [file: 'my_app.ex', line: 4]}]
IO.warn("variable bar is unused", stacktrace)
#=> warning: variable bar is unused
#=> my_app.ex:4: MyApp.main/1 write(device \\ :stdio, chardata)
Характеристики
write(device(), chardata() | String.Chars.t()) :: :ok
Записывает chardata в указанный device.
По умолчанию device — это стандартный вывод.
Примеры
IO.write("sample")
#=> sample
IO.write(:stderr, "error")
#=> error
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.9.4/IO.html