Fi

File 属于 Elixir

2 个练习

关于 File

处理文件的函数由File模块提供。

要读取整个文件,使用File.read/1。要写入文件,使用File.write/2。

该模块还提供用于复制、删除、重命名等操作的文件函数。它们的名称与 UNIX 中的对应命令相似,例如:

上面提到的 File 模块中的所有函数都有一个带!的变体,它抛出错误,而不是返回错误元组(例如File.read!/1)。如果你不打算处理文件不存在、权限不足这类错误,就用这个变体。

File.read("does_not_exist")
# => {:error, :enoent}

File.read!("does_not_exist")
# => ** (File.Error) could not read file "does_not_exist": no such file or directory
#        (elixir 1.10.4) lib/file.ex:353: File.read!/1

文件与进程

每次用File.write/2写入文件时,都会打开一个文件描述符,并启动一个新的 Elixir 进程。因此,应避免在循环中使用File.write/2写入文件。

改用File.open/2打开文件。File.open/2的第二个实参是一个模式列表,用来指定你是想以读取还是写入的方式打开文件。

常用的模式有:

  • :read:以读取方式打开,文件必须存在
  • :write:以写入方式打开,文件不存在时会创建,已有内容会被覆盖
  • :append:以写入方式打开,文件不存在时会创建,已有内容会保留

完整的模式列表见File.open/2的文档。

File.open/2返回处理该文件的进程的 PID。要读写该文件,使用IO模块中的函数,并把这个 PID 作为 IO 设备传入。

文件用完后,用File.close/1把它关闭。

file = File.open!("README.txt", [:write])
# => #PID<0.157.0>

IO.puts(file, "# README")
# => :ok

File.close(file)
# => :ok

流式处理文件

用File.read/1读取文件会一次性把整个文件加载到内存中。处理非常大的文件时,这可能是个问题。要高效地处理它们,你可以用File.open/2和IO.read/2逐行读取文件,也可以用File.stream/3把文件当作流来处理。这个流同时实现了Enumerable和Collectable这两种协议,也就是说,它既能用来读取,也能用来写入。

File.stream!("file.txt")
|> Stream.map(&(&1 <> "!"))
|> Stream.into(File.stream!("new_file.txt"))
|> Stream.run()

路径

所有处理文件的函数都需要一个文件路径。文件路径可以是绝对路径,也可以是相对于当前目录的相对路径。要操作路径,使用Path模块中的函数。为了跨平台兼容,请用Path.join/1来创建路径,它会选择适合当前平台的分隔符。

Path.expand(Path.join(["~", "documents", "important.txt"]))
"/home/user/documents/important.txt"
通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 File

练习已锁定

再解锁 1 个练习即可练习 File