查看源代码 io (stdlib v6.2)
标准 I/O 服务器接口函数。
此模块提供到标准 Erlang I/O 服务器的接口。输出函数如果成功都返回 ok
,如果不成功则会退出。
此模块中的所有函数都有一个可选参数 IoDevice
。如果包含此参数,则它必须是处理 I/O 协议的进程的 pid。通常,它是 file:open/2
返回的 IoDevice
。如果没有给出 IoDevice
,则使用 standard_io
。
有关 I/O 协议的描述,请参阅用户指南中的 Erlang I/O 协议部分。
警告
提供给函数
put_chars/2
的数据应为unicode:chardata/0
格式。这意味着向此函数提供二进制文件的程序必须先将其转换为 UTF-8,然后再尝试在 I/O 设备上输出数据。如果 I/O 设备设置为二进制模式,则函数
get_chars/2,3
和get_line/1,2
可以返回二进制文件而不是列表。二进制文件以 UTF-8 编码。要使用 ISO Latin-1 编码的二进制文件,请改用
file
模块。有关字符编码之间的转换函数,请参阅
unicode
模块。
错误信息
此模块中提到的 ErrorInfo
是从所有 I/O 模块返回的标准 ErrorInfo
结构。它具有以下格式
{ErrorLocation, Module, ErrorDescriptor}
使用以下调用获取描述错误的字符串
Module:format_error(ErrorDescriptor)
概述
类型
I/O 设备,可以是 standard_io/0
、standard_error/0
、user/0
、file:io_server/0
、注册的名称,或任何处理 I/O 协议的 pid。
当没有数据时,I/O 服务器发送的内容。
I/O 设备 standard_error
可用于将输出定向到当前操作系统认为适合错误输出的任何 I/O 设备。当标准输出被重定向时,这会很有用。
分配给进程的默认标准 I/O 设备。当此模块的函数调用中未指定 IoDevice
参数时,将使用此设备。
可用于与节点本地 stdout
和 stdin
交互的 I/O 设备。这可以是终端、管道、文件或它们的组合。
函数
检索 IoDevice
的列数(即终端的宽度)。
从 IoDevice
读取字符,使用 Prompt
提示。根据 Format
解释字符。
根据 Format
将 Data
中的项写入 IoDevice
。
从 IoDevice
读取 Count
个字符,使用 Prompt
提示。
从 IoDevice
读取一行,使用 Prompt
提示。
请求 IoDevice
的所有可用选项及其当前值。
等效于 nl(standard_io)
。
将换行符写入标准输出 (IoDevice
)。
从 IoDevice
读取数据,使用 Prompt
提示。
从 IoDevice
读取数据,使用 Prompt
提示。
返回用户请求的可打印 Unicode 字符范围。
将 CharData
的字符写入 IoDevice
。
从标准输入 (IoDevice
) 读取一个项 Term
,使用 Prompt
提示。
从 IoDevice
读取一个项 Term
,使用 Prompt
提示。
等效于 rows(standard_io)
。
检索 IoDevice
的行数(即终端的高度)。
从 IoDevice
读取数据,使用 Prompt
提示。
从 IoDevice
读取数据,使用 Prompt
提示。
为 IoDevice
设置选项。可能的选项和值因 I/O 设备而异。
将项 Term
写入 IoDevice
。
类型
-type device() :: atom() | pid() | file:io_server() | standard_io() | standard_error() | user().
I/O 设备,可以是 standard_io/0
、standard_error/0
、user/0
、file:io_server/0
、注册的名称,或任何处理 I/O 协议的 pid。
-type encoding() ::
latin1 | unicode | utf8 | utf16 | utf32 | {utf16, big | little} | {utf32, big | little}.
-type parse_form_ret() :: {ok, AbsForm :: erl_parse:abstract_form(), EndLocation :: erl_anno:location()} | {eof, EndLocation :: erl_anno:location()} | {error, ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(), ErrorLocation :: erl_anno:location()} | server_no_data().
-type parse_ret() :: {ok, ExprList :: [erl_parse:abstract_expr()], EndLocation :: erl_anno:location()} | {eof, EndLocation :: erl_anno:location()} | {error, ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(), ErrorLocation :: erl_anno:location()} | server_no_data().
-type prompt() :: atom() | unicode:chardata().
-type server_no_data() :: {error, ErrorDescription :: term()} | eof.
当没有数据时,I/O 服务器发送的内容。
-type setopt() :: binary | list | option().
-type standard_error() :: standard_error.
I/O 设备 standard_error
可用于将输出定向到当前操作系统认为适合错误输出的任何 I/O 设备。当标准输出被重定向时,这会很有用。
在类 Unix 操作系统上的示例
$ erl -noinput -eval 'io:format(standard_error,"Error: ~s~n",["error 11"]),'\
'init:stop().' > /dev/null
Error: error 11
-type standard_io() :: standard_io.
分配给进程的默认标准 I/O 设备。当此模块的函数调用中未指定 IoDevice
参数时,将使用此设备。
有时需要使用显式的 IoDevice
参数,该参数引用默认的 I/O 设备。在使用可以访问文件或默认 I/O 设备的函数时会出现这种情况。原子 standard_io
具有此特殊含义。以下示例对此进行了说明
27> io:read('enter>').
enter>foo.
{ok,foo}
28> io:read(standard_io, 'enter>').
enter>bar.
{ok,bar}
默认情况下,发送到 standard_io
的所有 I/O 都将最终发送到生成调用进程的节点的 user
I/O 设备。
standard_io
是 group_leader/0
的别名,因此为了更改默认输入/输出请求的发送位置,您可以使用 group_leader(NewGroupLeader, self())
更改当前进程的组长。
-type user() :: user.
可用于与节点本地 stdout
和 stdin
交互的 I/O 设备。这可以是终端、管道、文件或它们的组合。
使用 getopts/1
获取有关 I/O 设备的更多信息。
有关 user
如何处理 Unicode 的详细信息,请参阅 Erlang 用户指南中的 交互式 Shell 和 Escripts 和非交互式 I/O。
函数
-spec columns() -> {ok, pos_integer()} | {error, enotsup}.
等效于 columns(standard_io)
。
-spec columns(IoDevice) -> {ok, pos_integer()} | {error, enotsup} when IoDevice :: device().
检索 IoDevice
的列数(即终端的宽度)。
该函数对于终端设备成功执行,并为所有其他 I/O 设备返回 {error, enotsup}
。
-spec format(Format) -> ok when Format :: format().
等效于 format(Format, [])
。
-spec fread(IoDevice, Prompt, Format) -> Result when IoDevice :: device(), Prompt :: prompt(), Format :: format(), Result :: {ok, Terms :: [term()]} | {error, {fread, FreadError :: io_lib:fread_error()}} | server_no_data().
从 IoDevice
读取字符,使用 Prompt
提示。根据 Format
解释字符。
Format
可以包含以下内容
- 空白字符(空格、制表符和换行符),导致读取输入直到下一个非空白字符。
- 必须与下一个输入字符匹配的普通字符。
- 控制序列,其通用格式为
~*FMC
,其中- 字符
*
是一个可选的返回抑制字符。它提供了一种指定要省略的字段的方法。 F
是输入字段的字段宽度
。M
是一个可选的转换修饰符(其中t
是唯一支持的,表示 Unicode 转换)。C
确定控制序列的类型。
~
- 输入中应存在单个~
。d
- 预期为十进制整数。u
- 预期为 2-36 进制的无符号整数。字段宽度参数用于指定进制。不会跳过前导空白字符。-
- 预期为可选的符号字符。符号字符-
返回值-1
。符号字符+
或无符号返回1
。忽略字段宽度参数。不会跳过前导空白字符。#
- 预期为带有 Erlang 样式进制前缀的 2-36 进制整数(例如,"16#ffff"
)。f
- 预期为浮点数。它必须遵循 Erlang 浮点数语法。s
- 读取非空白字符的字符串。如果已指定字段宽度,则读取此数量的字符并剥离所有尾随空白字符。返回 Erlang 字符串(字符列表)。如果 Unicode 转换生效 (
~ts
),则接受 > 255 的字符,否则不接受。使用转换修饰符,返回的列表也可以因此包含 > 255 的整数1> io:fread("Prompt> ","~s"). Prompt> <Characters beyond latin1 range not printable in this medium> {error,{fread,string}} 2> io:fread("Prompt> ","~ts"). Prompt> <Characters beyond latin1 range not printable in this medium> {ok,[[1091,1085,1080,1094,1086,1076,1077]]}
a
- 类似于s
,但结果字符串转换为原子。c
- 读取等于字段宽度的字符数(默认为 1),并作为 Erlang 字符串返回。但是,不会像s
一样省略前导和尾随空白字符。返回所有字符。Unicode 转换修饰符的工作方式与
s
相同1> io:fread("Prompt> ","~c"). Prompt> <Character beyond latin1 range not printable in this medium> {error,{fread,string}} 2> io:fread("Prompt> ","~tc"). Prompt> <Character beyond latin1 range not printable in this medium> {ok,[[1091]]}
l
- 返回到该点为止已扫描的字符数,包括空白字符。
{ok, Terms}
- 读取成功,Terms
是成功匹配和读取的项的列表。eof
- 遇到文件结尾。{error, FreadError}
- 读取失败,FreadError
给出了有关错误的提示。{error, ErrorDescription}
- 读取操作失败,参数ErrorDescription
给出了有关错误的提示。
- 字符
示例
20> io:fread('enter>', "~f~f~f").
enter>1.9 35.5e3 15.0
{ok,[1.9,3.55e4,15.0]}
21> io:fread('enter>', "~10f~d").
enter> 5.67899
{ok,[5.678,99]}
22> io:fread('enter>', ":~10s:~10c:").
enter>: alan : joe :
{ok, ["alan", " joe "]}
-spec fwrite(Format) -> ok when Format :: format().
等效于 fwrite(Format, [])
。
-spec fwrite(IoDevice, Format, Data) -> ok when IoDevice :: device(), Format :: format(), Data :: [term()].
根据 Format
将 Data
中的项写入 IoDevice
。
Format
包含复制到输出设备的普通字符,以及用于格式化的控制序列,请参见下文。如果 Format
是原子或二进制,则首先借助 atom_to_list/1
或 binary_to_list/1
将其转换为列表。示例
1> io:fwrite("Hello world!~n", []).
Hello world!
ok
控制序列的通用格式为 ~F.P.PadModC
。
字符 C
确定要使用的控制序列类型。它是唯一必需的字段。所有 F
、P
、Pad
和 Mod
都是可选的。例如,要使用 #
作为 Pad
,但对 F
和 P
使用默认值,可以编写 ~..#C
。
F
是打印参数的字段宽度
。负值表示参数在字段内左对齐,否则为右对齐。如果未指定字段宽度,则使用所需的打印宽度。如果指定的字段宽度太小,则整个字段将填充*
字符。P
是打印参数的精度
。如果未指定精度,则使用默认值。精度的解释取决于控制序列。除非另有说明,否则使用参数within
来确定打印宽度。Pad
是填充字符。这是用于填充参数的打印表示形式的字符,以便其符合指定的字段宽度和精度。只能指定一个填充字符,并且在适用时,它将用于字段宽度和精度。默认填充字符是' '
(空格)。Mod
是控制序列修饰符。这是一个或多个更改Data
解释的字符。当前的修饰符是
t
- 用于 Unicode 转换。l
- 用于阻止p
和P
检测可打印字符。k
- 用于p
、P
、w
和W
,以按映射键ordered
顺序格式化映射(请参阅maps:iterator_order/0
)。K
- 类似于k
,用于按映射键顺序格式化映射,但采用一个额外的参数,用于指定maps:iterator_order/0
。例如
> M = #{ a => 1, b => 2 }. #{a => 1,b => 2} > io:format("~Kp~n", [reversed, M]). #{b => 2,a => 1} ok
如果 F
、P
或 Pad
是 *
字符,则使用 Data
中的下一个参数作为值。例如
1> io:fwrite("~*.*.0f~n",[9, 5, 3.14159265]).
003.14159
ok
要使用文字 *
字符作为 Pad
,必须将其作为参数传递
2> io:fwrite("~*.*.*f~n",[9, 5, $*, 3.14159265]).
**3.14159
ok
可用的控制序列
~
- 写入字符~
。c
- 该参数是一个被解释为 ASCII 代码的数字。精度是字符打印的次数,默认为字段宽度,字段宽度又默认为 1。示例1> io:fwrite("|~10.5c|~-10.5c|~5c|~n", [$a, $b, $c]). | aaaaa|bbbbb |ccccc| ok
如果 Unicode 转换修饰符 (
t
) 生效,则整数参数可以是表示有效 Unicode 代码点的任何数字,否则它应是小于或等于 255 的整数,否则使用 16#FF 屏蔽2> io:fwrite("~tc~n",[1024]). \x{400} ok 3> io:fwrite("~c~n",[1024]). ^@ ok
f
- 该参数是一个浮点数,写为[-]ddd.ddd
,其中精度是小数点后的位数。默认精度为 6,且不能 < 1。e
- 该参数是一个浮点数,写为[-]d.ddde+-ddd
,其中精度是写入的位数。默认精度为 6,且不能 < 2。g
- 如果参数 >= 0.1 且 < 10000.0,则该参数是一个浮点数,写为f
。否则,它以e
格式写入。精度是有效数字的位数。默认为 6,且不能 < 2。如果浮点数的绝对值不允许以所需的有效数字位数以f
格式写入,则也会以e
格式写入。s
- 使用字符串语法打印参数。如果不存在 Unicode 转换修饰符,则该参数是iolist/0
、binary/0
或atom/0
。如果 Unicode 转换修饰符 (t
) 生效,则该参数是unicode:chardata()
,这意味着二进制文件是 UTF-8 编码的。字符将不带引号打印。字符串首先会被指定的精度截断,然后填充并调整到指定的字段宽度。默认精度是字段宽度。此格式可用于打印任何对象并截断输出,使其适合指定的字段
1> io:fwrite("|~10w|~n", [{hey, hey, hey}]). |**********| ok 2> io:fwrite("|~10s|~n", [io_lib:write({hey, hey, hey})]). |{hey,hey,h| 3> io:fwrite("|~-10.8s|~n", [io_lib:write({hey, hey, hey})]). |{hey,hey | ok
如果未指定 Unicode 转换修饰符,则具有 > 255 的整数的列表被认为是错误
4> io:fwrite("~ts~n",[[1024]]). \x{400} ok 5> io:fwrite("~s~n",[[1024]]). ** exception error: bad argument in function io:format/3 called as io:format(<0.53.0>,"~s~n",[[1024]])
w
- 使用标准语法写入数据。这用于输出 Erlang 项。如果原子包含嵌入的不可打印字符,则在引号内打印。除非使用 Unicode 转换修饰符 (t
),否则原子字符 > 255 将被转义。浮点数将以最短的、正确舍入的字符串精确打印。p
- 使用与~w
相同的方式以标准语法写入数据,但会将打印表示形式长于一行的项分成多行,并合理缩进每一行。不支持左对齐。它还会尝试检测可打印字符的平面列表,并将这些列表输出为字符串。例如1> T = [{attributes,[[{id,age,1.50000},{mode,explicit}, {typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]}, {typename,'Person'},{tag,{'PRIVATE',3}},{mode,implicit}]. ... 2> io:fwrite("~w~n", [T]). [{attributes,[[{id,age,1.5},{mode,explicit},{typename, [73,78,84,69,71,69,82]}],[{id,cho},{mode,explicit},{typena me,'Cho'}]]},{typename,'Person'},{tag,{'PRIVATE',3}},{mode ,implicit}] ok 3> io:fwrite("~62p~n", [T]). [{attributes,[[{id,age,1.5}, {mode,explicit}, {typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]}, {typename,'Person'}, {tag,{'PRIVATE',3}}, {mode,implicit}] ok
字段宽度指定最大行长度。默认为 80。精度指定项的初始缩进。它默认为在相同调用
write/1
或format/1,2,3
时此行上打印的字符数。例如,使用上面的T
4> io:fwrite("Here T = ~62p~n", [T]). Here T = [{attributes,[[{id,age,1.5}, {mode,explicit}, {typename,"INTEGER"}], [{id,cho}, {mode,explicit}, {typename,'Cho'}]]}, {typename,'Person'}, {tag,{'PRIVATE',3}}, {mode,implicit}] ok
从 Erlang/OTP 21.0 开始,可以使用字段宽度值
0
来指定行是无限长的,这意味着不会插入换行符。例如5> io:fwrite("~0p~n", [lists:seq(1, 30)]). [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30] ok
当指定修饰符
l
时,不会进行可打印字符列表的检测,例如6> S = [{a,"a"}, {b, "b"}], io:fwrite("~15p~n", [S]). [{a,"a"}, {b,"b"}] ok 7> io:fwrite("~15lp~n", [S]). [{a,[97]}, {b,[98]}] ok
Unicode 转换修饰符
t
指定如何处理拉丁语-1 代码点范围之外的字符(在原子、字符串和二进制文件中)。例如,打印包含 > 255 字符的原子8> io:fwrite("~p~n",[list_to_atom([1024])]). '\x{400}' ok 9> io:fwrite("~tp~n",[list_to_atom([1024])]). 'Ѐ' ok
默认情况下,Erlang 仅检测拉丁语-1 范围内的字符列表作为字符串,但是可以使用
+pc unicode
标志来更改此设置(有关详细信息,请参阅printable_range/0
)。例如10> io:fwrite("~p~n",[[214]]). "Ö" ok 11> io:fwrite("~p~n",[[1024]]). [1024] ok 12> io:fwrite("~tp~n",[[1024]]). [1024] ok
但是,如果 Erlang 使用
+pc unicode
启动13> io:fwrite("~p~n",[[1024]]). [1024] ok 14> io:fwrite("~tp~n",[[1024]]). "Ѐ" ok
类似地,如果指定
t
修饰符,则看起来像 UTF-8 编码字符串的二进制文件将使用二进制字符串语法输出15> io:fwrite("~p~n", [<<208,128>>]). <<208,128>> ok 16> io:fwrite("~tp~n", [<<208,128>>]). <<"Ѐ"/utf8>> ok 17> io:fwrite("~tp~n", [<<128,128>>]). <<128,128>> ok
W
- 以与~w
相同的方式写入数据,但接受一个额外的参数,即打印术语的最大深度。任何低于此深度的内容都将替换为...
。例如,使用上面的T
8> io:fwrite("~W~n", [T,9]). [{attributes,[[{id,age,1.5},{mode,explicit},{typename,...}], [{id,cho},{mode,...},{...}]]},{typename,'Person'}, {tag,{'PRIVATE',3}},{mode,implicit}] ok
如果达到最大深度,则无法在结果输出中读取。此外,元组中的
,...
形式表示元组中还有更多元素,但这些元素低于打印深度。P
- 以与~p
相同的方式写入数据,但接受一个额外的参数,即打印术语的最大深度。任何低于此深度的内容都将替换为...
,例如9> io:fwrite("~62P~n", [T,9]). [{attributes,[[{id,age,1.5},{mode,explicit},{typename,...}], [{id,cho},{mode,...},{...}]]}, {typename,'Person'}, {tag,{'PRIVATE',3}}, {mode,implicit}] ok
B
- 以 2-36 为基数写入整数,默认基数为 10。负整数会打印前导短划线。精度字段选择基数,例如
1> io:fwrite("~.16B~n", [31]). 1F ok 2> io:fwrite("~.2B~n", [-19]). -10011 ok 3> io:fwrite("~.36B~n", [5*36+35]). 5Z ok
X
- 类似于B
,但接受一个额外的参数,该参数是要插入到数字之前的前缀,但在前导短划线(如果有)之后。前缀可以是可能很深的一系列字符或一个原子。示例
1> io:fwrite("~X~n", [31,"10#"]). 10#31 ok 2> io:fwrite("~.16X~n", [-31,"0x"]). -0x1F ok
#
- 类似于B
,但使用 Erlang 风格的#
分隔的基数前缀打印数字。示例1> io:fwrite("~.10#~n", [31]). 10#31 ok 2> io:fwrite("~.16#~n", [-31]). -16#1F ok
b
- 类似于B
,但打印小写字母。x
- 类似于X
,但打印小写字母。+
- 类似于#
,但打印小写字母。n
- 写入新行。i
- 忽略下一个术语。
该函数返回
ok
- 格式化成功。
如果发生错误,则没有输出。示例
1> io:fwrite("~s ~w ~i ~w ~c ~n",['abc def', 'abc def', {foo, 1},{foo, 1}, 65]).
abc def 'abc def' {foo,1} A
ok
2> io:fwrite("~s", [65]).
** exception error: bad argument
in function io:format/3
called as io:format(<0.53.0>,"~s","A")
在此示例中,尝试使用字符串格式化指令 "~s"
输出单个字符 65。
-spec get_chars(Prompt, Count) -> Data | server_no_data() when Prompt :: prompt(), Count :: non_neg_integer(), Data :: string() | unicode:unicode_binary().
-spec get_chars(IoDevice, Prompt, Count) -> Data | server_no_data() when IoDevice :: device(), Prompt :: prompt(), Count :: non_neg_integer(), Data :: string() | unicode:unicode_binary().
从 IoDevice
读取 Count
个字符,使用 Prompt
提示。
该函数返回
Data
- 输入字符。如果 I/O 设备支持 Unicode,则数据可以表示代码点 > 255(latin1
范围)。如果 I/O 服务器设置为传递二进制文件,则它们以 UTF-8 编码(无论 I/O 设备是否支持 Unicode)。如果要将数据作为 latin1 编码的二进制文件返回,则应改用file:read/2
。eof
- 遇到文件结尾。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
-spec get_line(Prompt) -> Data | server_no_data() when Prompt :: prompt(), Data :: string() | unicode:unicode_binary().
-spec get_line(IoDevice, Prompt) -> Data | server_no_data() when IoDevice :: device(), Prompt :: prompt(), Data :: string() | unicode:unicode_binary().
从 IoDevice
读取一行,使用 Prompt
提示。
该函数返回
Data
- 以换行符(或文件结尾)结尾的行中的字符。如果 I/O 设备支持 Unicode,则数据可以表示代码点 > 255(latin1
范围)。如果 I/O 服务器设置为传递二进制文件,则它们以 UTF-8 编码(无论 I/O 设备是否支持 Unicode)。如果要将数据作为 latin1 编码的二进制文件返回,则应改用file:read_line/1
。eof
- 遇到文件结尾。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
等效于 getopts(standard_io)
。
-spec getopts(IoDevice) -> [getopt()] | {error, Reason} when IoDevice :: device(), Reason :: term().
请求 IoDevice
的所有可用选项及其当前值。
例如
1> {ok,F} = file:open("/dev/null",[read]).
{ok,<0.42.0>}
2> io:getopts(F).
[{binary,false},{encoding,latin1}]
此处,文件 I/O 服务器返回文件的所有可用选项,这些选项是预期的选项,encoding
和 binary
。但是,标准 shell 还有更多选项
3> io:getopts().
[{expand_fun,#Fun<group.0.120017273>},
{echo,true},
{binary,false},
{encoding,unicode},
{terminal,true},
{stdout,true},
{stderr,true},
{stdin,true}]
正如所见,此示例是在终端支持 Unicode 输入和输出的环境中运行的。
stdin
、stdout
和 stderr
选项是只读的,并指示流是否为终端。当它是终端时,Erlang 运行的大多数系统允许使用 ANSI 转义码来控制终端的输入或输出。
terminal
是 stdout
的别名。
有关其他选项的说明,请参阅 setopts/1
。
-spec nl() -> ok.
等效于 nl(standard_io)
。
-spec nl(IoDevice) -> ok when IoDevice :: device().
将换行符写入标准输出 (IoDevice
)。
-spec parse_erl_exprs(IoDevice, Prompt, StartLocation) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Result :: parse_ret().
-spec parse_erl_exprs(IoDevice, Prompt, StartLocation, Options) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Options :: erl_scan:options(), Result :: parse_ret().
从 IoDevice
读取数据,使用 Prompt
提示。
从位置 StartLocation
开始读取。参数 Options
作为函数 erl_scan:tokens/4
的参数 Options
传递。数据被标记化和解析,就像它是一系列 Erlang 表达式一样,直到达到最后一个点 (.
)。
该函数返回
{ok, ExprList, EndLocation}
- 解析成功。{eof, EndLocation}
- 标记器遇到文件结尾。eof
- I/O 服务器遇到文件结尾。{error, ErrorInfo, ErrorLocation}
- 标记化或解析时发生错误。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
示例
25> io:parse_erl_exprs('enter>').
enter>abc(), "hey".
{ok, [{call,1,{atom,1,abc},[]},{string,1,"hey"}],2}
26> io:parse_erl_exprs('enter>').
enter>abc("hey".
{error,{1,erl_parse,["syntax error before: ",["'.'"]]},2}
-spec parse_erl_form(Prompt) -> Result when Prompt :: prompt(), Result :: parse_form_ret().
-spec parse_erl_form(IoDevice, Prompt) -> Result when IoDevice :: device(), Prompt :: prompt(), Result :: parse_form_ret().
-spec parse_erl_form(IoDevice, Prompt, StartLocation) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Result :: parse_form_ret().
-spec parse_erl_form(IoDevice, Prompt, StartLocation, Options) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Options :: erl_scan:options(), Result :: parse_form_ret().
从 IoDevice
读取数据,使用 Prompt
提示。
从位置 StartLocation
开始读取。参数 Options
作为函数 erl_scan:tokens/4
的参数 Options
传递。数据被标记化和解析,就像它是一个 Erlang 形式(Erlang 源文件中有效的 Erlang 表达式之一),直到达到最后一个点 (.
)。
该函数返回
{ok, AbsForm, EndLocation}
- 解析成功。{eof, EndLocation}
- 标记器遇到文件结尾。eof
- I/O 服务器遇到文件结尾。{error, ErrorInfo, ErrorLocation}
- 标记化或解析时发生错误。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
-spec printable_range() -> unicode | latin1.
返回用户请求的可打印 Unicode 字符范围。
用户可以请求一系列字符,这些字符将在 shell 和格式化函数通过启发式方法检测字符串时被视为可打印的。这可以通过在启动 Erlang 时提供 +pc <range>
来完成。
<range>
的唯一有效值是 latin1
和 unicode
。latin1
表示仅代码点 < 256(控制字符等除外)被视为可打印的。unicode
表示所有 Unicode 字符范围中的所有可打印字符都被 I/O 函数视为可打印的。
默认情况下,启动 Erlang 时,仅 latin1
范围的字符表示整数列表是一个字符串。
使用该设置的最简单方法是调用 io_lib:printable_list/1
,它使用此函数的返回值来确定列表是否为可打印字符的字符串。
注意
在未来的版本中,此函数可能会返回更多值和范围。为避免兼容性问题,建议使用函数
io_lib:printable_list/1
。
-spec put_chars(CharData) -> ok when CharData :: unicode:chardata().
-spec put_chars(IoDevice, CharData) -> ok when IoDevice :: device(), CharData :: unicode:chardata().
将 CharData
的字符写入 IoDevice
。
如果要将 latin1 编码的字节写入 IoDevice
,则应改用 file:write/2
。
-spec read(Prompt) -> Result when Prompt :: prompt(), Result :: {ok, Term :: term()} | server_no_data() | {error, ErrorInfo}, ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
-spec read(IoDevice, Prompt) -> Result when IoDevice :: device(), Prompt :: prompt(), Result :: {ok, Term :: term()} | server_no_data() | {error, ErrorInfo}, ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
从标准输入 (IoDevice
) 读取一个项 Term
,使用 Prompt
提示。
该函数返回
{ok, Term}
- 解析成功。eof
- 遇到文件结尾。{error, ErrorInfo}
- 解析失败。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
-spec read(IoDevice, Prompt, StartLocation) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Result :: {ok, Term :: term(), EndLocation :: erl_anno:location()} | {eof, EndLocation :: erl_anno:location()} | server_no_data() | {error, ErrorInfo, ErrorLocation :: erl_anno:location()}, ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
-spec read(IoDevice, Prompt, StartLocation, Options) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Options :: erl_scan:options(), Result :: {ok, Term :: term(), EndLocation :: erl_anno:location()} | {eof, EndLocation :: erl_anno:location()} | server_no_data() | {error, ErrorInfo, ErrorLocation :: erl_anno:location()}, ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
从 IoDevice
读取一个项 Term
,使用 Prompt
提示。
读取从位置 StartLocation
开始。参数 Options
作为函数 erl_scan:tokens/4
的参数 Options
传递。
该函数返回
{ok, Term, EndLocation}
- 解析成功。{eof, EndLocation}
- 遇到文件结尾。{error, ErrorInfo, ErrorLocation}
- 解析失败。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
-spec rows() -> {ok, pos_integer()} | {error, enotsup}.
等效于 rows(standard_io)
。
-spec rows(IoDevice) -> {ok, pos_integer()} | {error, enotsup} when IoDevice :: device().
检索 IoDevice
的行数(即终端的高度)。
该函数仅对终端设备成功,对于所有其他 I/O 设备,该函数返回 {error, enotsup}
。
-spec scan_erl_exprs(Prompt) -> Result when Prompt :: prompt(), Result :: erl_scan:tokens_result() | server_no_data().
-spec scan_erl_exprs(Device, Prompt) -> Result when Device :: device(), Prompt :: prompt(), Result :: erl_scan:tokens_result() | server_no_data().
-spec scan_erl_exprs(Device, Prompt, StartLocation) -> Result when Device :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Result :: erl_scan:tokens_result() | server_no_data().
-spec scan_erl_exprs(Device, Prompt, StartLocation, Options) -> Result when Device :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Options :: erl_scan:options(), Result :: erl_scan:tokens_result() | server_no_data().
从 IoDevice
读取数据,使用 Prompt
提示。
读取从位置 StartLocation
开始。参数 Options
作为函数 erl_scan:tokens/4
的参数 Options
传递。数据被标记化,就像它是一系列 Erlang 表达式一样,直到达到最后一个点 (.
)。此标记也会返回。
该函数返回
{ok, Tokens, EndLocation}
- 标记化成功。{eof, EndLocation}
- 标记器遇到文件结尾。eof
- I/O 服务器遇到文件结尾。{error, ErrorInfo, ErrorLocation}
- 标记化时发生错误。{error, ErrorDescription}
- 其他(罕见)错误情况,例如,如果从 NFS 文件系统读取,则为{error, estale}
。
示例
23> io:scan_erl_exprs('enter>').
enter>abc(), "hey".
{ok,[{atom,1,abc},{'(',1},{')',1},{',',1},{string,1,"hey"},{dot,1}],2}
24> io:scan_erl_exprs('enter>').
enter>1.0er.
{error,{1,erl_scan,{illegal,float}},2}
-spec scan_erl_form(Prompt) -> Result when Prompt :: prompt(), Result :: erl_scan:tokens_result() | server_no_data().
-spec scan_erl_form(IoDevice, Prompt) -> Result when IoDevice :: device(), Prompt :: prompt(), Result :: erl_scan:tokens_result() | server_no_data().
-spec scan_erl_form(IoDevice, Prompt, StartLocation) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Result :: erl_scan:tokens_result() | server_no_data().
-spec scan_erl_form(IoDevice, Prompt, StartLocation, Options) -> Result when IoDevice :: device(), Prompt :: prompt(), StartLocation :: erl_anno:location(), Options :: erl_scan:options(), Result :: erl_scan:tokens_result() | server_no_data().
从 IoDevice
读取数据,使用 Prompt
提示。
从位置 StartLocation
(1
) 开始读取。参数 Options
作为函数 erl_scan:tokens/4
的参数 Options
传递。数据被标记化,就像它是一个 Erlang 形式(Erlang 源文件中有效的 Erlang 表达式之一),直到达到最后一个点 (.
)。也会返回最后一个标记。
返回值与 scan_erl_exprs/4
的返回值相同。
-spec setopts(IoDevice, Opts) -> ok | {error, Reason} when IoDevice :: device(), Opts :: [setopt()], Reason :: term().
为 IoDevice
设置选项。可能的选项和值因 I/O 设备而异。
有关特定 I/O 设备上支持的选项及其当前值的列表,请使用函数 getopts/1
。
OTP I/O 设备支持的选项和值如下
binary
、list
或{binary, boolean()}
- 如果设置为二进制模式(binary
或{binary, true}
),则 I/O 服务器会向get_line
、get_chars
和(如果可能)get_until
请求发送二进制数据(以 UTF-8 编码)作为答案(有关详细信息,请参阅用户指南中的“Erlang I/O 协议”部分)。直接效果是,get_chars/2,3
和get_line/1,2
为受影响的 I/O 设备返回 UTF-8 二进制文件,而不是字符列表。默认情况下,OTP 中的所有 I/O 设备都设置为
list
模式。但是,I/O 函数可以处理任何这些模式,因此其他用户编写的模块也应该像 I/O 服务器的客户端一样工作。此选项受
standard_io/0
、user/0
和file:io_server/0
I/O 服务器支持。{echo, boolean()}
- 表示终端是否回显输入。仅标准 shell I/O 服务器(group.erl
)支持此选项。{expand_fun, expand_fun()}
- 提供一个类似于 Erlang shell 的 tab 补全(扩展)函数。当用户按下 Tab 键时,会调用此函数。当调用诸如get_line/1,2
等行读取函数时,扩展功能处于激活状态。该函数被调用时,会将当前行(直到光标处)作为反转的字符串传入。它需要返回一个三元组:
{yes|no, string(), list()}
。如果第一个元素为no
,则发出蜂鸣声,否则扩展是静默的;第二个元素是一个将在光标位置输入的字符串;第三个元素是可能的扩展列表。如果此列表不为空,则会将其打印在当前输入行的下方。可能的扩展列表可以以不同的方式格式化,以便让更高级的扩展建议对用户来说更易读,请参阅edlin_expand:expand/2
文档以了解更多信息。简单示例(除空行外,任何其他输入都会发出蜂鸣声,空行会被扩展为
"quit"
)fun("") -> {yes, "quit", []}; (_) -> {no, "", ["quit"]} end
此选项仅由标准 shell(
group.erl
)支持。{log, none | output | input | all}
- 告知 I/O 服务器应该记录 I/O 请求。请求将以info
级别记录到[otp, kernel, io, input | output | ctrl]
域,并带有以下报告#{ request := IoRequest, server := pid(), server_name => term() }.
需要特别注意的是,应格外小心,以确保这些日志报告不会被记录到
standard_io/0
,因为这可能导致系统进入无限循环。示例
1> logger:set_primary_config(level, info). ok 2> logger:add_handler(stdout, logger_std_h, #{ config => #{ file => "stdout.log" }}). ok 3> io:setopts(user, [{log, output}]). ok 4> io:format(user, "Hello~n", []). Hello ok 5> file:read_file("stdout.log"). {ok,<<"2024-11-14T09:53:49.275085+01:00 info: <0.89.0> wrote to user, Hello\n">>}
并非所有 I/O 服务器都支持此选项。请使用
io:getopts/1
来检查它是否可用。注意
Erlang/OTP 中的 I/O 服务器会将 logger 域设置为
[otp, kernel, io, input | output]
。默认的logger
处理程序不会打印此域,因此您需要启用它。这可以通过添加类似这样的新过滤器来完成logger:add_handler_filter(default, io_domain, {fun logger_filters:domain/2, {log,sub,[otp,kernel,io]}}).
{encoding, latin1 | unicode}
- 指定字符从 I/O 设备输入或输出的方式,这意味着,例如,终端设置为处理 Unicode 输入和输出,或者文件设置为处理 UTF-8 数据编码。此选项不影响从 I/O 函数返回数据的方式,也不影响在 I/O 协议中发送数据的方式,它仅影响 I/O 设备如何处理到“物理”设备的 Unicode 字符。
系统启动时,标准 shell 设置为
unicode
或latin1
编码。编码通过类 Unix 系统上的LANG
或LC_CTYPE
环境变量或在其他系统上通过其他方式设置。因此,如果 I/O 设备支持,用户可以输入 Unicode 字符,并且 I/O 设备处于{encoding, unicode}
模式。如果运行时系统的假设错误,可以通过设置此选项来更改模式。注意
在 OTP 26.0 之前,当 Erlang 使用
-oldshell
或-noshell
标志启动时(例如,在escript
中),standard_io
的默认编码设置为latin1
,这意味着任何大于代码点 255 的字符都会被转义,并且输入应为纯 8 位 ISO Latin-1。从 OTP 26.0 开始,如果standard_io
支持 Unicode,则始终默认为unicode
,否则为latin1
。如果您想在
standard_io
上发送原始字节,您现在始终需要显式地将编码设置为latin1
;否则,代码点 128-255 将被转换为 UTF-8。最好通过将内核配置参数 standard_io_encoding 设置为latin1
来完成此操作。文件也可以设置为
{encoding, unicode}
,这意味着数据以 UTF-8 格式写入和读取。文件可以有更多的编码,请参阅下文。标准 shell(
group.erl
,包括 Windows 上的werl
)、“oldshell”(user.erl
)和文件 I/O 服务器都支持{encoding, unicode | latin1}
。{encoding, utf8 | utf16 | utf32 | {utf16,big} | {utf16,little} | {utf32,big} | {utf32,little}}
- 对于磁盘文件,编码可以设置为各种 UTF 变体。这将导致数据被期望以指定编码从文件中读取,并且数据以指定编码写入到磁盘文件。{encoding, utf8}
在文件上具有与{encoding, unicode}
相同的效果。扩展编码仅在磁盘文件(通过函数
file:open/2
打开的文件)上受支持。
-spec write(Term) -> ok when Term :: term().
将项 Term
写入 IoDevice
。