Skip to content

Commit 9baa4d4

Browse files
committed
旧文更新
1 parent d6668fd commit 9baa4d4

File tree

5 files changed

+181
-156
lines changed

5 files changed

+181
-156
lines changed

12-io.md

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
12-I/O
22
======
3-
[I/O模块](#121-io%E6%A8%A1%E5%9D%97) <br/>
4-
[文件模块](#122-%E6%96%87%E4%BB%B6%E6%A8%A1%E5%9D%97) <br/>
5-
[路径模块](#123-%E8%B7%AF%E5%BE%84%E6%A8%A1%E5%9D%97) <br/>
6-
[进程和组长](#124-%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%BB%84%E9%95%BF) <br/>
7-
[*iodata**chardata*](#125-iodata%E5%92%8Cchardata) <br/>
8-
9-
本章简单介绍Elixir的输入、输出机制,以及相关的模块,如[IO](http://elixir-lang.org/docs/stable/elixir/IO.html)
3+
[I/O模块](#121-io%E6%A8%A1%E5%9D%97)
4+
[文件模块](#122-%E6%96%87%E4%BB%B6%E6%A8%A1%E5%9D%97)
5+
[路径模块](#123-%E8%B7%AF%E5%BE%84%E6%A8%A1%E5%9D%97)
6+
[进程和组长](#124-%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%BB%84%E9%95%BF)
7+
[*iodata**chardata*](#125-iodata%E5%92%8Cchardata)
8+
9+
本章简单介绍Elixir的输入、输出机制以及相关的模块,
10+
[IO](http://elixir-lang.org/docs/stable/elixir/IO.html)
1011
[文件](http://elixir-lang.org/docs/stable/elixir/File.html)
1112
[路径](http://elixir-lang.org/docs/stable/elixir/Path.html)
1213

@@ -15,7 +16,7 @@
1516
##12.1-IO模块
1617
IO模块是Elixir语言中读写标准输入、输出、标准错误、文件、设备的主要机制。
1718
使用该模块的方法颇为直接:
18-
```
19+
```elixir
1920
iex> IO.puts "hello world"
2021
"hello world"
2122
:ok
@@ -26,16 +27,17 @@ yes or no? yes
2627

2728
IO模块中的函数默认使用标准输入输出。
2829
我们也可以传递```:stderr```来指示将错误信息写到标准错误设备上:
29-
```
30+
```elixir
3031
iex> IO.puts :stderr, "hello world"
3132
"hello world"
3233
:ok
3334
```
3435

3536
#12.2-文件模块
3637
文件模块包含了可以让我们读写文件的函数。
37-
默认情况下文件是以二进制模式打开,它要求程序员使用特殊的```IO.binread/2``````IO.binwrite/2```函数来读写文件:
38-
```
38+
默认情况下文件是以二进制模式打开,它要求程序员使用特殊的```IO.binread/2```
39+
```IO.binwrite/2```函数来读写文件:
40+
```elixir
3941
iex> {:ok, file} = File.open "hello", [:write]
4042
{:ok, #PID<0.47.0>}
4143
iex> IO.binwrite file, "world"
@@ -47,20 +49,22 @@ iex> File.read "hello"
4749
```
4850

4951
文件可以使用```:utf8```编码打开,然后就可以被IO模块中其他函数使用了:
50-
```
52+
```elixir
5153
iex> {:ok, file} = File.open "another", [:write, :utf8]
5254
{:ok, #PID<0.48.0>}
5355
```
5456

55-
除了打开、读写文件的函数,文件模块还有许多函数来操作文件系统。这些函数根据Unix功能相对应的命令命名。
56-
```File.rm/1```用来删除文件;```File.mkdir/1```用来创建目录;```File.mkdir_p/1```创建目录并保证其父目录一并创建;
57+
除了打开、读写文件的函数,文件模块还有许多函数来操作文件系统。
58+
这些函数根据Unix功能相对应的命令命名。
59+
```File.rm/1```用来删除文件;```File.mkdir/1```
60+
用来创建目录;```File.mkdir_p/1```创建目录并保证其父目录一并创建;
5761
还有```File.cp_r/2``````File.rm_rf/2```用来递归地复制和删除整个目录。
5862

5963

60-
你还会注意到文件模块中,函数一般有一个名称类似的版本。区别是名称上一个有!(bang)一个没有。
64+
你还会注意到文件模块中,一般函数都有一个名称类似的版本。区别是名称上一个有!(bang)一个没有。
6165
例如,上面的例子我们在读取“hello”文件时,用的是不带!号的版本。
6266
下面用例子演示下它们的区别:
63-
```
67+
```elixir
6468
iex> File.read "hello"
6569
{:ok, "world"}
6670
iex> File.read! "hello"
@@ -71,49 +75,51 @@ iex> File.read! "unknown"
7175
** (File.Error) could not read file unknown: no such file or directory
7276
```
7377

74-
注意看,当文件不存在时,带!号的版本会报错。就是说不带!号的版本能照顾到模式匹配出来的不同的情况。
75-
但有的时候,你就是希望文件在那儿,!使得它能报出有意义的错误。
78+
注意看,当文件不存在时,带!号的版本会报错。就是说不带!号的版本能照顾到模式匹配出来的不同情况。
79+
但有的时候,你就是希望文件在那儿,!使得它能报出有意义的错误。
80+
7681
因此,不要写:
77-
```
82+
```elixir
7883
{:ok, body} = File.read(file)
7984
```
8085

8186
相反地,应该这么写:
82-
```
87+
```elixir
8388
case File.read(file) do
8489
{:ok, body} -> # handle ok
8590
{:error, r} -> # handle error
8691
end
8792
```
8893
或者
89-
```
94+
```elixir
9095
File.read!(file)
9196
```
9297

9398
## 12.3-路径模块
9499
文件模块中绝大多数函数都以路径作为参数。通常这些路径都是二进制,可以被路径模块提供的函数操作:
95-
```
100+
```elixir
96101
iex> Path.join("foo", "bar")
97102
"foo/bar"
98103
iex> Path.expand("~/hello")
99104
"/Users/jose/hello"
100105
```
101106

102-
<br/>
103107

104108
有了以上介绍的几个模块和函数,我们已经能对文件系统进行基本的IO操作。
105-
下面将讨论IO令人好奇的高级话题。这部分不是写Elixir程序必须掌握的,可以跳过不看。
106-
但是如果你大概地看看,可以了解一下IO是如何在VM上实现以及其它一些有趣的内容
109+
下面将讨论I/O模块中令人好奇的高级话题。这部分不是写Elixir程序必须掌握的,可以跳过不看。
110+
但是如果你大概地浏览一下,可以了解IO是如何在VM上实现以及其它一些有趣的内容
107111

108112
## 12.4-进程和组长
109113
你可能已经发现,```File.open/2```函数返回了一个包含PID的元祖:
110-
```
114+
```elixir
111115
iex> {:ok, file} = File.open "hello", [:write]
112116
{:ok, #PID<0.47.0>}
113-
```
114-
这是因为IO模块实际上是同进程协同工作的。当你调用```IO.write(pid, binary)```时,IO模块将发送一条消息给执行操作的进程。
117+
```
118+
119+
I/O模块实际上是同进程协同工作的。当你调用```IO.write(pid, binary)```时,
120+
I/O模块将发送一条消息给执行操作的进程。
115121
让我们用自己的代码表述下这个过程:
116-
```
122+
```elixir
117123
iex> pid = spawn fn ->
118124
...> receive do: (msg -> IO.inspect msg)
119125
...> end
@@ -123,21 +129,23 @@ iex> IO.write(pid, "hello")
123129
** (ErlangError) erlang error: :terminated
124130
```
125131

126-
调用```IO.write/2```之后,可以看见打印出了发给IO模块的请求。然而因为我们没有提供某些东西,这个请求失败了。
132+
调用```IO.write/2```之后,可以看见打印出了发给IO模块的请求。
133+
然而因为我们没有提供某些东西,这个请求失败了。
127134

128-
[StringIO模块](http://elixir-lang.org/docs/stable/elixir/StringIO.html)提供了一个基于字符串的IO实现:
129-
```
135+
[StringIO模块](http://elixir-lang.org/docs/stable/elixir/StringIO.html)
136+
提供了一个基于字符串的IO实现:
137+
```elixir
130138
iex> {:ok, pid} = StringIO.open("hello")
131139
{:ok, #PID<0.43.0>}
132140
iex> IO.read(pid, 2)
133141
"he"
134142
```
135143

136-
Erlang虚拟机用进程给IO设备建模,允许同一个网络中的不同节点通过交换文件进程,实现节点间的文件读写。
137-
在所有IO设备之中,有一个特殊的进程,称作组长(group leader)。
144+
Erlang虚拟机用进程给I/O设备建模,允许同一个网络中的不同节点通过交换文件进程,
145+
实现节点间的文件读写。在所有IO设备之中,有一个特殊的进程,称作组长(group leader)。
138146

139147
当你写东西到标准输出,实际上是发送了一条消息给组长,它把内容写给*STDIO文件表述者*
140-
```
148+
```elixir
141149
iex> IO.puts :stdio, "hello"
142150
hello
143151
:ok
@@ -151,11 +159,12 @@ hello
151159

152160
## 12.5-*iodata**chardata*
153161
在以上所有例子中,我们都用的是二进制/字符串方式读写文件。
154-
在“二进制、字符串和字符列表”那章里,我们注意到字符串就是普通的bytes,而字符列表是code points的列表。
162+
在“二进制、字符串和字符列表”那章里,我们注意到字符串就是普通的bytes,
163+
而字符列表是code points(字符码)的列表。
155164

156-
157-
IO模块和文件模块中的函数接受列表作为参数。这也就算了,其实还可以接受混合类型的列表,里面是整形、二进制都行:
158-
```
165+
I/O模块和文件模块中的函数接受列表作为参数。
166+
还可以接受混合类型的列表,里面内容是整形、二进制都行:
167+
```elixir
159168
iex> IO.puts 'hello world'
160169
hello world
161170
:ok
@@ -164,10 +173,12 @@ hello world
164173
:ok
165174
```
166175

167-
尽管如此,有些地方还是要注意。一个列表可能表示一串byte,或者一串字符。用哪一种看IO设备是怎么编码的。
168-
如果不指明编码,文件就以raw模式打开,这时候只能用文件模块里bin*开头(二进制版)的函数对其进行操作。
169-
这些函数接受*iodata*作为参数,即,它们期待一个整数值的列表,用来表示byte或二进制。
176+
尽管如此,有些地方还是要注意。一个列表可能表示一串byte,或者一串字符。
177+
用哪一种需要看I/O设备是怎么编码的。
170178

171-
尽管只是细微的差别,但你只需要考虑那些细节,如果你打算传递列表给那些函数。
172-
底层的bytes已经可以表示二进制,这种表示就是raw的。
179+
如果不指明编码,文件就以raw模式打开,这时候只能用文件模块里bin*开头(二进制版)
180+
的函数对其进行操作。
181+
这些函数接受*iodata*作为参数,即,它们期待一个整数值的列表,用来表示byte或二进制。
173182

183+
尽管只是细微的差别,如果你打算传递列表给那些函数,你需要考虑那些细节。
184+
底层的bytes可以表示二进制,这种表示就是raw的。

0 commit comments

Comments
 (0)