查看源代码 文件 (Elixir v1.16.2)

此模块包含用于操作文件的功能。

其中一些函数是低级函数,允许用户与文件或 IO 设备进行交互,例如 open/2copy/3 等。该模块还提供高级函数,这些函数使用文件名,并根据 Unix 变体进行命名。例如,可以使用 cp/3 复制文件,可以使用 rm_rf/1 递归地删除文件和目录。

传递给此模块中函数的路径可以是相对于当前工作目录(由 File.cwd/0 返回)的路径,也可以是绝对路径。shell 约定(例如 ~)不会自动展开。要使用像 ~/Downloads 这样的路径,可以使用 Path.expand/1Path.expand/2 将路径展开为绝对路径。

编码

为了写入和读取文件,必须使用 IO 模块中的函数。默认情况下,文件以二进制模式打开,这需要使用 IO.binread/2IO.binwrite/2 函数与文件进行交互。开发人员可以在打开文件时传递 :utf8 作为选项,然后必须使用较慢的 IO.read/2IO.write/2 函数,因为它们负责执行适当的转换并提供适当的数据保证。

请注意,在 Elixir 中,作为字符列表给出的文件名始终被视为 UTF-8。具体来说,我们预计 shell 和操作系统已配置为使用 UTF-8 编码。二进制文件名被视为原始数据,并按原样传递给操作系统。

API

此模块中的大多数函数在成功时返回 :ok{:ok, result},在失败时返回 {:error, reason}。这些函数还有以 ! 结尾的变体,它们在成功时返回结果(而不是 {:ok, result} 元组),在失败时则引发异常。例如

File.read("hello.txt")
#=> {:ok, "World"}

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

File.read!("hello.txt")
#=> "World"

File.read!("invalid.txt")
#=> raises File.Error

一般来说,如果开发人员想要在文件不存在时做出反应,则应使用前者。如果开发人员期望他们的软件在无法读取文件时失败(即,它确实是异常),则应使用后者。

进程和原始文件

每次打开文件时,Elixir 都会生成一个新进程。写入文件等同于向写入文件描述符的进程发送消息。

这意味着文件可以在节点之间传递,消息传递保证它们可以写入网络中的同一个文件。

但是,您可能并不总是想要为此抽象付出代价。在这种情况下,文件可以以 :raw 模式打开。当操作大型文件或在紧凑循环中处理文件时,:read_ahead:delayed_write 选项也很有用。

有关这些选项和其他性能注意事项的更多信息,请查看 :file.open/2

在文件中查找

您还可以使用 :file 模块中的任何函数与 Elixir 返回的文件进行交互。例如,要从文件中的特定位置读取,请使用 :file.pread/3

File.write!("example.txt", "Eats, Shoots & Leaves")
file = File.open!("example.txt")
:file.pread(file, 15, 6)
#=> {:ok, "Leaves"}

或者,如果您需要跟踪当前位置,请使用 :file.position/2:file.read/2

:file.position(file, 6)
#=> {:ok, 6}
:file.read(file, 6)
#=> {:ok, "Shoots"}
:file.position(file, {:cur, -12})
#=> {:ok, 0}
:file.read(file, 4)
#=> {:ok, "Eats"}

摘要

函数

设置当前工作目录。

cd/1 相同,但如果失败,则引发 File.Error 异常。

将当前目录更改为给定的 path,执行给定的函数,然后无论是否存在异常都恢复到之前的路径。

更改给定 file 的组 ID gid 指定的组。成功时返回 :ok,失败时返回 {:error, reason}

chgrp/2 相同,但在失败时引发 File.Error 异常。否则返回 :ok

更改给定 filemode

chmod/2 相同,但在失败时引发 File.Error 异常。否则返回 :ok

更改给定 file 的用户 ID uid 指定的拥有者。成功时返回 :ok,失败时返回 {:error, reason}

chown/2 相同,但在失败时引发 File.Error 异常。否则返回 :ok

关闭 io_device 引用的文件。它主要返回 :ok,除了内存不足等严重错误。

source 的内容复制到 destination

copy/3 相同,但在失败时引发 File.CopyError 异常。否则返回 bytes_copied

source_file 的内容复制到 destination_file,同时保留其模式。

cp/3 相同,但在失败时引发 File.CopyError 异常。否则返回 :ok

递归地将 source 中的内容复制到 destination,同时维护源目录结构和模式。

cp_r/3 相同,但在失败时引发 File.CopyError 异常。否则返回已复制文件的列表。

获取当前工作目录。

cwd/0 相同,但如果失败,则引发 File.Error 异常。

如果给定的路径是目录,则返回 true

如果给定的路径存在,则返回 true

为文件 existing 创建硬链接 new

ln/2 相同,但在失败时引发 File.LinkError 异常。否则返回 :ok

为文件或目录 existing 创建符号链接 new

ln_s/2 相同,但在失败时引发 File.LinkError 异常。否则返回 :ok

返回给定目录中的文件列表。

ls/1 相同,但在发生错误时引发 File.Error 异常。

返回有关 path 的信息。如果文件是符号链接,则将 type 设置为 :symlink,并返回链接的 File.Stat 结构体。对于任何其他文件,返回与 stat/2 完全相同的返回值。

lstat/2 相同,但直接返回 File.Stat 结构体,或者在返回错误时引发 File.Error 异常。

尝试创建目录 path

mkdir/1 相同,但在失败时引发 File.Error 异常。否则返回 :ok

尝试创建目录 path

mkdir_p/1 相同,但在失败时引发 File.Error 异常。否则返回 :ok

打开给定的 path

类似于 open/2,但期望一个函数作为其最后一个参数。

类似于 open/2,但在无法打开文件时引发 File.Error 异常。否则返回 IO 设备。

类似于 open/3,但在无法打开文件时引发 File.Error 异常。

返回 {:ok, binary},其中 binary 是一个包含 path 内容的二进制数据对象,或者如果发生错误则返回 {:error, reason}

返回给定文件名的内容的二进制数据,或者在发生错误时引发 File.Error 异常。

读取 path 处的符号链接。

read_link/1 相同,但直接返回目标,或者在返回错误时引发 File.Error 异常。

如果路径是普通文件,则返回 true

source 文件重命名为 destination 文件。它可用于在目录之间移动文件(和目录)。如果移动文件,则必须完全指定 destination 文件名,仅指定其目录是不够的。

rename/2 相同,但在失败时引发 File.RenameError 异常。否则返回 :ok

尝试删除文件 path

rm/1 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

递归地删除给定 path 下的文件和目录。不会跟踪符号链接,而是直接删除它们,不存在的文件将被忽略(即不会导致此函数失败)。

rm_rf/1 相同,但在失败的情况下会引发 File.Error 异常,否则返回已删除的文件或目录列表。

尝试删除 path 下的目录。

rmdir/1 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

返回有关 path 的信息。如果存在,则返回一个 {:ok, info} 元组,其中 info 是一个 File.Stat 结构体。如果发生错误,则返回 {:error, reason},错误原因与 read/1 相同。

stat/2 相同,但直接返回 File.Stat,如果返回错误则引发 File.Error 异常。

为给定 path 返回一个带有给定 modesFile.Stream

更新给定文件的修改时间 (mtime) 和访问时间 (atime)。

touch/2 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

content 写入文件 path

write/3 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

将给定的 File.Stat 写回文件系统中的给定路径。返回 :ok{:error, reason}

write_stat/3 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

类型

@type encoding_mode() ::
  :utf8
  | {:encoding,
     :latin1
     | :unicode
     | :utf8
     | :utf16
     | :utf32
     | {:utf16, :big | :little}
     | {:utf32, :big | :little}}
@type erlang_time() ::
  {{year :: non_neg_integer(), month :: 1..12, day :: 1..31},
   {hour :: 0..23, minute :: 0..59, second :: 0..59}}
@type io_device() :: :file.io_device()
@type mode() ::
  :append
  | :binary
  | :charlist
  | :compressed
  | :delayed_write
  | :exclusive
  | :raw
  | :read
  | :read_ahead
  | :sync
  | :write
  | {:read_ahead, pos_integer()}
  | {:delayed_write, non_neg_integer(), non_neg_integer()}
  | encoding_mode()
链接到此类型

on_conflict_callback()

查看源代码
@type on_conflict_callback() :: (Path.t(), Path.t() -> boolean())
@type posix() :: :file.posix()
@type posix_time() :: integer()
@type read_offset_mode() :: {:read_offset, non_neg_integer()}
@type stat_options() :: [{:time, :local | :universal | :posix}]
@type stream_mode() ::
  encoding_mode()
  | read_offset_mode()
  | :append
  | :compressed
  | :delayed_write
  | :trim_bom
  | {:read_ahead, pos_integer() | false}
  | {:delayed_write, non_neg_integer(), non_neg_integer()}

函数

@spec cd(Path.t()) :: :ok | {:error, posix()}

设置当前工作目录。

当前工作目录是在 BEAM 中全局设置的。如果多个进程同时更改当前工作目录,这可能会导致竞争条件。要在不更改全局当前工作目录的情况下在给定目录中运行外部命令,请使用 System.cmd/3Port.open/2:cd 选项。

如果成功,则返回 :ok,否则返回 {:error, reason}

@spec cd!(Path.t()) :: :ok

cd/1 相同,但如果失败,则引发 File.Error 异常。

@spec cd!(Path.t(), (-> res)) :: res when res: var

将当前目录更改为给定的 path,执行给定的函数,然后无论是否存在异常都恢复到之前的路径。

当前工作目录在 BEAM 中被临时全局设置。如果多个进程同时更改当前工作目录,这可能会导致竞争条件。要在不更改全局当前工作目录的情况下在给定目录中运行外部命令,请使用 System.cmd/3Port.open/2:cd 选项。

如果检索或更改当前目录失败,则会引发错误。

@spec chgrp(Path.t(), non_neg_integer()) :: :ok | {:error, posix()}

更改给定 file 的组 ID gid 指定的组。成功时返回 :ok,失败时返回 {:error, reason}

@spec chgrp!(Path.t(), non_neg_integer()) :: :ok

chgrp/2 相同,但在失败时引发 File.Error 异常。否则返回 :ok

@spec chmod(Path.t(), non_neg_integer()) :: :ok | {:error, posix()}

更改给定 filemode

成功时返回 :ok,失败时返回 {:error, reason}

权限

文件权限通过将以下八进制模式相加来指定

  • 0o400 - 读取权限:所有者

  • 0o200 - 写入权限:所有者

  • 0o100 - 执行权限:所有者

  • 0o040 - 读取权限:组

  • 0o020 - 写入权限:组

  • 0o010 - 执行权限:组

  • 0o004 - 读取权限:其他

  • 0o002 - 写入权限:其他

  • 0o001 - 执行权限:其他

例如,将模式设置为 0o755 将赋予所有者写入、读取和执行权限,以及组和其他人读取和执行权限。

@spec chmod!(Path.t(), non_neg_integer()) :: :ok

chmod/2 相同,但在失败时引发 File.Error 异常。否则返回 :ok

@spec chown(Path.t(), non_neg_integer()) :: :ok | {:error, posix()}

更改给定 file 的用户 ID uid 指定的拥有者。成功时返回 :ok,失败时返回 {:error, reason}

@spec chown!(Path.t(), non_neg_integer()) :: :ok

chown/2 相同,但在失败时引发 File.Error 异常。否则返回 :ok

@spec close(io_device()) :: :ok | {:error, posix() | :badarg | :terminated}

关闭 io_device 引用的文件。它主要返回 :ok,除了内存不足等严重错误。

注意,如果在打开文件时使用了 :delayed_write 选项,close/1 可能会返回旧的写入错误,甚至不会尝试关闭文件。有关详细信息,请参见 open/2

链接到此函数

copy(source, destination, bytes_count \\ :infinity)

查看源代码
@spec copy(Path.t() | io_device(), Path.t() | io_device(), pos_integer() | :infinity) ::
  {:ok, non_neg_integer()} | {:error, posix()}

source 的内容复制到 destination

两个参数都可以是使用 open/2 打开的文件名或 IO 设备。 bytes_count 指定要复制的字节数,默认值为 :infinity

如果文件 destination 已经存在,它将被 source 中的内容覆盖。

如果成功,则返回 {:ok, bytes_copied},否则返回 {:error, reason}

cp/3 相比,此函数更底层,允许按字节数限制将内容从一个设备复制到另一个设备。另一方面,cp/3 对源和目标进行更广泛的检查,并且还保留复制后的文件模式。

常见的错误原因与 open/2read/1write/3 中的错误原因相同。

链接到此函数

copy!(source, destination, bytes_count \\ :infinity)

查看源代码
@spec copy!(Path.t() | io_device(), Path.t() | io_device(), pos_integer() | :infinity) ::
  non_neg_integer()

copy/3 相同,但在失败时引发 File.CopyError 异常。否则返回 bytes_copied

链接到此函数

cp(source_file, destination_file, options \\ [])

查看源代码
@spec cp(Path.t(), Path.t(), [{:on_conflict, on_conflict_callback()}]) ::
  :ok | {:error, posix()}

source_file 的内容复制到 destination_file,同时保留其模式。

source_file 必须是文件或指向文件的符号链接。 destination_file 必须是指向不存在文件的路径。如果两者都是目录,则将返回 {:error, :eisdir}

如果函数成功,则返回 :ok。否则,它将返回 {:error, reason}

如果您想将内容从一个 IO 设备复制到另一个设备,或者直接将内容从源复制到目标而不保留模式,请查看 copy/3

注意:Unix 类系统中的 cp 命令的行为不同,具体取决于目标是现有目录还是其他目录。我们选择明确禁止复制到目标目录,如果尝试这样做,将返回错误。

选项

  • :on_conflict - (自 v1.14.0 起) 当目标中已存在文件时调用。该函数接收 source_filedestination_file 的参数。如果现有文件应该被覆盖,它应该返回 true,否则返回 false。默认回调返回 true。在早期版本中,此回调可以作为第三个参数给出,但现在这种行为已过时。
链接到此函数

cp!(source_file, destination_file, options \\ [])

查看源代码
@spec cp!(Path.t(), Path.t(), [{:on_conflict, on_conflict_callback()}]) :: :ok

cp/3 相同,但在失败时引发 File.CopyError 异常。否则返回 :ok

链接到此函数

cp_r(source, destination, options \\ [])

查看源代码
@spec cp_r(Path.t(), Path.t(),
  on_conflict: on_conflict_callback(),
  dereference_symlinks: boolean()
) ::
  {:ok, [binary()]} | {:error, posix(), binary()}

递归地将 source 中的内容复制到 destination,同时维护源目录结构和模式。

如果 source 是文件或指向文件的符号链接,则 destination 必须是指向现有文件、指向现有文件的符号链接或指向不存在文件的路径。

如果 source 是目录或指向目录的符号链接,则 destination 必须是现有 directory 或指向目录的符号链接,或指向不存在目录的路径。

如果源是文件,则将 source 复制到 destination。如果 source 是目录,则将源内部的内容复制到 destination 目录中。

如果目标中已存在文件,则会调用作为选项给出的可选 on_conflict 回调。有关详细信息,请参见“选项”。

此函数在复制文件时可能会失败,在这种情况下,它会将目标目录处于混乱状态,其中已复制的文件不会被删除。

如果函数成功,则返回 {:ok, files_and_directories}files_and_directories 以非特定顺序列出所有复制的文件和目录。否则,它将返回 {:error, reason, file}

注意:Unix 类系统中的 cp 命令的行为不同,具体取决于 destination 是现有目录还是其他目录。我们选择明确禁止此行为。如果 sourcefiledestination 是目录,则将返回 {:error, :eisdir}

选项

  • :on_conflict - (自 v1.14.0 起) 当目标中已存在文件时调用。该函数接收 sourcedestination 的参数。如果现有文件应该被覆盖,它应该返回 true,否则返回 false。默认回调返回 true。在早期版本中,此回调可以作为第三个参数给出,但现在这种行为已过时。

  • :dereference_symlinks - (自 v1.14.0 起) 默认情况下,此函数会通过创建指向相同位置的符号链接来复制符号链接。如果此选项设置为 true,则会强制对符号链接进行解除引用,并复制其内容。如果解除引用的文件不存在,则操作将失败。默认值为 false

示例

# Copies file "a.txt" to "b.txt"
File.cp_r("a.txt", "b.txt")

# Copies all files in "samples" to "tmp"
File.cp_r("samples", "tmp")

# Same as before, but asks the user how to proceed in case of conflicts
File.cp_r("samples", "tmp", on_conflict: fn source, destination ->
  IO.gets("Overwriting #{destination} by #{source}. Type y to confirm. ") == "y\n"
end)
链接到此函数

cp_r!(source, destination, options \\ [])

查看源代码
@spec cp_r!(Path.t(), Path.t(),
  on_conflict: on_conflict_callback(),
  dereference_symlinks: boolean()
) ::
  [binary()]

cp_r/3 相同,但在失败时引发 File.CopyError 异常。否则返回已复制文件的列表。

@spec cwd() :: {:ok, binary()} | {:error, posix()}

获取当前工作目录。

在极少数情况下,此函数在 Unix 类系统上可能会失败。如果当前目录的父目录不存在读取权限,则可能会发生这种情况。因此,如果成功,则返回 {:ok, cwd},否则返回 {:error, reason}

@spec cwd!() :: binary()

cwd/0 相同,但如果失败,则引发 File.Error 异常。

链接到此函数

dir?(path, opts \\ [])

查看源代码
@spec dir?(Path.t(), [dir_option]) :: boolean() when dir_option: :raw

如果给定的路径是目录,则返回 true

此函数会跟踪符号链接,因此如果符号链接指向目录,则返回 true

选项

支持的选项是

  • :raw - 单个原子,绕过文件服务器,仅检查本地文件

示例

File.dir?("./test")
#=> true

File.dir?("test")
#=> true

File.dir?("/usr/bin")
#=> true

File.dir?("~/Downloads")
#=> false

"~/Downloads" |> Path.expand() |> File.dir?()
#=> true
链接到此函数

exists?(path, opts \\ [])

查看源代码
@spec exists?(Path.t(), [exists_option]) :: boolean() when exists_option: :raw

如果给定的路径存在,则返回 true

它可以是普通文件、目录、套接字、符号链接、命名管道或设备文件。对于指向不存在目标的符号链接,返回 false

选项

支持的选项是

  • :raw - 单个原子,绕过文件服务器,仅检查本地文件

示例

File.exists?("test/")
#=> true

File.exists?("missing.txt")
#=> false

File.exists?("/dev/null")
#=> true
链接到此函数

ln(existing, new)

查看源代码 (自 1.5.0 起)
@spec ln(Path.t(), Path.t()) :: :ok | {:error, posix()}

为文件 existing 创建硬链接 new

如果成功,则返回 :ok,否则返回 {:error, reason}。如果操作系统不支持硬链接,则返回 {:error, :enotsup}

链接到此函数

ln!(existing, new)

查看源代码 (自 1.5.0 起)
@spec ln!(Path.t(), Path.t()) :: :ok

ln/2 相同,但在失败时引发 File.LinkError 异常。否则返回 :ok

链接到此函数

ln_s(existing, new)

查看源代码 (自 1.5.0 起)
@spec ln_s(Path.t(), Path.t()) :: :ok | {:error, posix()}

为文件或目录 existing 创建符号链接 new

如果成功,则返回 :ok,否则返回 {:error, reason}。如果操作系统不支持符号链接,则返回 {:error, :enotsup}

@spec ln_s!(Path.t(), Path.t()) :: :ok

ln_s/2 相同,但在失败时引发 File.LinkError 异常。否则返回 :ok

@spec ls(Path.t()) :: {:ok, [binary()]} | {:error, posix()}

返回给定目录中的文件列表。

隐藏文件不会被忽略,结果也不会被排序。

由于目录被文件系统视为文件,因此它们也包含在返回值中。

如果成功,则返回 {:ok, files},否则返回 {:error, reason}

@spec ls!(Path.t()) :: [binary()]

ls/1 相同,但在发生错误时引发 File.Error 异常。

链接到此函数

lstat(path, opts \\ [])

查看源代码
@spec lstat(Path.t(), stat_options()) :: {:ok, File.Stat.t()} | {:error, posix()}

返回有关 path 的信息。如果文件是符号链接,则将 type 设置为 :symlink,并返回链接的 File.Stat 结构体。对于任何其他文件,返回与 stat/2 完全相同的返回值。

有关更多详细信息,请参见 :file.read_link_info/2

选项

接受的选项包括

  • :time - 配置如何返回文件时间戳

:time 的值可以是

  • :universal - 以 UTC 返回 {date, time} 元组(默认)
  • :local - 使用机器时间返回 {date, time} 元组
  • :posix - 将时间以自纪元以来的整数秒数返回

注意:由于文件时间在大多数操作系统上以 POSIX 时间格式存储,因此使用 time: :posix 选项检索文件信息的速度更快。

链接到此函数

lstat!(path, opts \\ [])

查看源代码
@spec lstat!(Path.t(), stat_options()) :: File.Stat.t()

lstat/2 相同,但直接返回 File.Stat 结构体,或者在返回错误时引发 File.Error 异常。

@spec mkdir(Path.t()) :: :ok | {:error, posix()}

尝试创建目录 path

不会创建缺失的父目录。如果成功,则返回 :ok,如果发生错误,则返回 {:error, reason}

常见的错误原因包括

  • :eacces - 缺少 path 父目录的搜索或写入权限
  • :eexist - 已经存在名为 path 的文件或目录
  • :enoent - path 的一个组件不存在
  • :enospc - 设备上没有剩余空间
  • :enotdir - path 的一个组件不是目录;在某些平台上,会返回 :enoent
@spec mkdir!(Path.t()) :: :ok

mkdir/1 相同,但在失败时引发 File.Error 异常。否则返回 :ok

@spec mkdir_p(Path.t()) :: :ok | {:error, posix()}

尝试创建目录 path

会创建缺失的父目录。如果成功,则返回 :ok,如果发生错误,则返回 {:error, reason}

常见的错误原因包括

  • :eacces - 缺少 path 父目录的搜索或写入权限
  • :enospc - 设备上没有剩余空间
  • :enotdir - path 的一个组件不是目录
@spec mkdir_p!(Path.t()) :: :ok

mkdir_p/1 相同,但在失败时引发 File.Error 异常。否则返回 :ok

链接到此函数

open(path, modes_or_function \\ [])

查看源代码
@spec open(Path.t(), [mode() | :ram]) :: {:ok, io_device()} | {:error, posix()}
@spec open(Path.t(), (io_device() -> res)) :: {:ok, res} | {:error, posix()}
when res: var

打开给定的 path

为了写入和读取文件,必须使用 IO 模块中的函数。默认情况下,文件以 :binary 模式打开,这需要 IO.binread/2IO.binwrite/2 函数与文件进行交互。开发人员可以在打开文件时传递 :utf8 作为选项,然后来自 IO 的所有其他函数都可用,因为它们直接使用 Unicode 数据。

modes_or_function 可以是模式列表或函数。如果它是一个列表,则它被视为模式列表(在下面有文档说明)。如果它是一个函数,则它等效于调用 open(path, [], modes_or_function)。有关此函数的更多信息,请参见 open/3 的文档。

允许的模式

  • :binary - 以二进制模式打开文件,禁用对 Unicode 序列的特殊处理(默认模式)。

  • :read - 文件必须存在,以供读取打开。

  • :write - 文件以供写入打开。如果它不存在,则会创建它。

    如果文件存在,并且写入没有与读取组合,则文件将被截断。

  • :append - 文件将以供写入打开,如果它不存在,则会创建它。对以追加模式打开的文件的每次写入操作都将发生在文件末尾。

  • :exclusive - 文件在以供写入打开时,如果它不存在,则会创建它。如果文件存在,open 将返回 {:error, :eexist}

  • :charlist - 当给出此项时,对文件的读取操作将返回字符列表而不是二进制。

  • :compressed - 使读取或写入 gzip 压缩文件成为可能。

    compressed 选项必须与读取或写入结合使用,但不能同时使用两者。请注意,通过 stat/1 获得的文件大小很可能与可以从压缩文件中读取的字节数不匹配。

  • :utf8 - 此选项表示数据实际存储在磁盘文件中的方式,并使文件自动将字符转换为 UTF-8 并从 UTF-8 转换。

    如果数据以无法转换为 UTF-8 的格式发送到文件,或者数据被返回以无法处理数据的字符范围的格式返回数据的函数读取,则会发生错误,并且文件将被关闭。

  • :delayed_write, :raw, :ram, :read_ahead, :sync, {:encoding, ...}, {:read_ahead, pos_integer}, {:delayed_write, non_neg_integer, non_neg_integer} - 有关这些选项的更多信息,请参见 :file.open/2

此函数返回

  • {:ok, io_device} - 文件已以请求的模式打开。

    io_device 实际上是处理文件的进程的 PID。此进程监控最初打开文件的进程(所有者进程)。如果所有者进程终止,则文件将被关闭,进程本身也将终止。如果与 io_device 链接的任何进程终止,则文件将被关闭,进程本身也将终止。

    从该调用返回的 io_device 可以用作 IO 模块函数的参数。

  • {:error, reason} - 文件无法打开。

示例

{:ok, file} = File.open("foo.tar.gz", [:read, :compressed])
IO.read(file, :line)
File.close(file)
链接到此函数

open(path, modes, function)

查看源代码
@spec open(Path.t(), [mode() | :ram], (io_device() -> res)) ::
  {:ok, res} | {:error, posix()}
when res: var

类似于 open/2,但期望一个函数作为其最后一个参数。

文件被打开,作为参数传递给函数,并在函数返回后自动关闭,无论执行函数时是否发生错误。

如果成功,则返回 {:ok, function_result},否则返回 {:error, reason}

此函数期望文件成功关闭,通常情况如此,除非给出 :delayed_write 选项。因此,我们不建议将 :delayed_write 传递给此函数。

示例

File.open("file.txt", [:read, :write], fn file ->
  IO.read(file, :line)
end)

有关可用 modes 的列表,请参见 open/2

链接到此函数

open!(path, modes_or_function \\ [])

查看源代码
@spec open!(Path.t(), [mode() | :ram]) :: io_device()
@spec open!(Path.t(), (io_device() -> res)) :: res when res: var

类似于 open/2,但在无法打开文件时引发 File.Error 异常。否则返回 IO 设备。

有关可用模式的列表,请参见 open/2

链接到此函数

open!(path, modes, function)

查看源代码
@spec open!(Path.t(), [mode() | :ram], (io_device() -> res)) :: res when res: var

类似于 open/3,但在无法打开文件时引发 File.Error 异常。

如果它成功打开文件,则它将在 IO 设备上返回 function 结果。

有关可用 modes 的列表,请参见 open/2

@spec read(Path.t()) :: {:ok, binary()} | {:error, posix()}

返回 {:ok, binary},其中 binary 是一个包含 path 内容的二进制数据对象,或者如果发生错误则返回 {:error, reason}

常见的错误原因

  • :enoent - 文件不存在
  • :eacces - 缺少读取文件的权限,或缺少搜索其父目录之一的权限
  • :eisdir - 指定的文件是一个目录
  • :enotdir - 文件名的一个组件不是目录;在某些平台上,会返回 :enoent
  • :enomem - 文件的内容没有足够的内存

可以使用 :file.format_error/1 获取错误的描述性字符串。

@spec read!(Path.t()) :: binary()

返回给定文件名的内容的二进制数据,或者在发生错误时引发 File.Error 异常。

链接到此函数

read_link(path)

查看源代码 (自 1.5.0 起)
@spec read_link(Path.t()) :: {:ok, binary()} | {:error, posix()}

读取 path 处的符号链接。

如果 path 存在并且是一个符号链接,则返回 {:ok, target},否则返回 {:error, reason}

有关更多详细信息,请参见 :file.read_link/1

常见的错误原因包括

  • :einval - path 不是符号链接
  • :enoent - path 不存在
  • :enotsup - 当前平台不支持符号链接
链接到此函数

read_link!(path)

查看源代码 (自 1.5.0 起)
@spec read_link!(Path.t()) :: binary()

read_link/1 相同,但直接返回目标,或者在返回错误时引发 File.Error 异常。

链接到此函数

regular?(path, opts \\ [])

查看源代码
@spec regular?(Path.t(), [regular_option]) :: boolean() when regular_option: :raw

如果路径是普通文件,则返回 true

此函数会遵循符号链接,因此如果符号链接指向一个普通文件,则会返回 true

选项

支持的选项是

  • :raw - 单个原子,绕过文件服务器,仅检查本地文件

示例

File.regular?(__ENV__.file)
#=> true
链接到此函数

rename(source, destination)

查看源代码 (自 1.1.0 起)
@spec rename(Path.t(), Path.t()) :: :ok | {:error, posix()}

source 文件重命名为 destination 文件。它可用于在目录之间移动文件(和目录)。如果移动文件,则必须完全指定 destination 文件名,仅指定其目录是不够的。

如果成功,则返回 :ok,否则返回 {:error, reason}

注意:Unix 类系统中的 mv 命令的行为不同,具体取决于 source 是文件,而 destination 是现有的目录。我们选择明确禁止此行为。

示例

# Rename file "a.txt" to "b.txt"
File.rename("a.txt", "b.txt")

# Rename directory "samples" to "tmp"
File.rename("samples", "tmp")
链接到此函数

rename!(source, destination)

查看源代码 (自 1.9.0 起)
@spec rename!(Path.t(), Path.t()) :: :ok

rename/2 相同,但在失败时引发 File.RenameError 异常。否则返回 :ok

@spec rm(Path.t()) :: :ok | {:error, posix()}

尝试删除文件 path

如果成功,则返回 :ok,如果发生错误,则返回 {:error, reason}

注意,即使在只读模式下也会删除文件。

常见的错误原因包括

  • :enoent - 文件不存在
  • :eacces - 缺少文件或其父目录之一的权限
  • :eperm - 文件是一个目录,并且用户不是超级用户
  • :enotdir - 文件名的一个组件不是目录;在某些平台上,会返回 :enoent
  • :einval - 文件名类型不正确,例如元组

示例

File.rm("file.txt")
#=> :ok

File.rm("tmp_dir/")
#=> {:error, :eperm}
@spec rm!(Path.t()) :: :ok

rm/1 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

@spec rm_rf(Path.t()) :: {:ok, [binary()]} | {:error, posix(), binary()}

递归地删除给定 path 下的文件和目录。不会跟踪符号链接,而是直接删除它们,不存在的文件将被忽略(即不会导致此函数失败)。

返回 {:ok, files_and_directories},其中包含按无特定顺序删除的所有文件和目录,否则返回 {:error, reason, file}

示例

File.rm_rf("samples")
#=> {:ok, ["samples", "samples/1.txt"]}

File.rm_rf("unknown")
#=> {:ok, []}
@spec rm_rf!(Path.t()) :: [binary()]

rm_rf/1 相同,但在失败的情况下会引发 File.Error 异常,否则返回已删除的文件或目录列表。

@spec rmdir(Path.t()) :: :ok | {:error, posix()}

尝试删除 path 下的目录。

如果成功,则返回 :ok,如果发生错误,则返回 {:error, reason}。如果目录不为空,则返回 {:error, :eexist}

示例

File.rmdir("tmp_dir")
#=> :ok

File.rmdir("non_empty_dir")
#=> {:error, :eexist}

File.rmdir("file.txt")
#=> {:error, :enotdir}
@spec rmdir!(Path.t()) :: :ok | {:error, posix()}

rmdir/1 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

链接到此函数

stat(path, opts \\ [])

查看源代码
@spec stat(Path.t(), stat_options()) :: {:ok, File.Stat.t()} | {:error, posix()}

返回有关 path 的信息。如果存在,则返回一个 {:ok, info} 元组,其中 info 是一个 File.Stat 结构体。如果发生错误,则返回 {:error, reason},错误原因与 read/1 相同。

选项

接受的选项包括

  • :time - 配置如何返回文件时间戳

:time 的值可以是

  • :universal - 以 UTC 返回 {date, time} 元组(默认)
  • :local - 使用与机器相同的时区返回 {date, time} 元组
  • :posix - 将时间以自纪元以来的整数秒数返回

注意:由于文件时间在大多数操作系统上以 POSIX 时间格式存储,因此使用 time: :posix 选项检索文件信息的速度更快。

链接到此函数

stat!(path, opts \\ [])

查看源代码
@spec stat!(Path.t(), stat_options()) :: File.Stat.t()

stat/2 相同,但直接返回 File.Stat,如果返回错误则引发 File.Error 异常。

链接到此函数

stream!(path, line_or_bytes_modes \\ [])

查看源代码
@spec stream!(Path.t(), :line | pos_integer() | [stream_mode()]) :: File.Stream.t()

File.stream!/3 的简写。

链接到此函数

stream!(path, line_or_bytes, modes)

查看源代码
@spec stream!(Path.t(), :line | pos_integer(), [stream_mode()]) :: File.Stream.t()

为给定 path 返回一个带有给定 modesFile.Stream

流同时实现了 EnumerableCollectable 协议,这意味着它既可以用于读取也可以用于写入。

line_or_bytes 参数配置流式传输时如何读取文件,通过 :line(默认)或通过给定的字节数。使用 :line 选项时,CRLF 换行符 ("\r\n") 将被规范化为 LF ("\n")。

与其他文件操作类似,流可以在一个节点中创建并转发到另一个节点。一旦流在另一个节点中打开,将向创建者节点发送请求以生成一个用于文件流式传输的进程。

操作流可能会在打开时因与 File.open!/2 相同的原因而失败。请注意,每次流式传输开始时都会自动打开文件。无需传递 :read:write 模式,因为这些模式由 Elixir 自动设置。

原始文件

由于 Elixir 控制着流文件何时打开,底层设备无法共享,因此为了性能考虑,最好以原始模式打开文件。 因此,如果流在创建它的同一节点中打开并且没有指定编码,Elixir **将** 以 :raw 模式打开流,并使用 :read_ahead 选项。 这意味着流入文件的任何数据必须转换为 iodata/0 类型。 如果你传递,例如,[encoding: :utf8][encoding: {:utf16, :little}] 在 modes 参数中,底层流将使用 IO.write/2String.Chars 协议来转换数据。 查看 IO.binwrite/2IO.write/2

如果流打算在紧密循环中写入,也可以考虑传递 :delayed_write 选项。

字节顺序标记和读取偏移量

如果你在 modes 参数中传递 :trim_bom,流将在从文件读取时修剪 UTF-8、UTF-16 和 UTF-32 字节顺序标记。

请注意,此函数不会尝试根据 BOM 发现文件编码。 从 Elixir v1.16.0 开始,你还可以传递一个 :read_offset,该偏移量在枚举流时会被跳过(如果同时提供了 :read_offset:trim_bom,则会在 BOM 之后跳过偏移量)。

示例

# Read a utf8 text file which may include BOM
File.stream!("./test/test.txt", [:trim_bom, encoding: :utf8])

# Read in 2048 byte chunks rather than lines
File.stream!("./test/test.data", 2048)

查看 Stream.run/1,了解流入文件的示例。

链接到此函数

touch(path, time \\ System.os_time(:second))

查看源代码
@spec touch(Path.t(), erlang_time() | posix_time()) :: :ok | {:error, posix()}

更新给定文件的修改时间 (mtime) 和访问时间 (atime)。

如果文件不存在,则会创建该文件。 需要以 UTC 时间表示的日期时间(如 :erlang.universaltime() 返回)或表示 POSIX 时间戳的整数(如 System.os_time(:second) 返回)。

在类 Unix 系统中,更改修改时间可能需要你具有 root 权限或文件的拥有者权限。 具有写入权限可能还不够。 在这些情况下,第一次触摸文件(以创建文件)将成功,但触摸现有文件将失败,并显示 {:error, :eperm}

示例

File.touch("/tmp/a.txt", {{2018, 1, 30}, {13, 59, 59}})
#=> :ok
File.touch("/fakedir/b.txt", {{2018, 1, 30}, {13, 59, 59}})
{:error, :enoent}

File.touch("/tmp/a.txt", 1544519753)
#=> :ok
链接到此函数

touch!(path, time \\ System.os_time(:second))

查看源代码
@spec touch!(Path.t(), erlang_time() | posix_time()) :: :ok

touch/2 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

如果文件不存在,则会创建该文件。 需要以 UTC 时间表示的日期时间(如 :erlang.universaltime() 返回)或表示 POSIX 时间戳的整数(如 System.os_time(:second) 返回)。

示例

File.touch!("/tmp/a.txt", {{2018, 1, 30}, {13, 59, 59}})
#=> :ok
File.touch!("/fakedir/b.txt", {{2018, 1, 30}, {13, 59, 59}})
** (File.Error) could not touch "/fakedir/b.txt": no such file or directory

File.touch!("/tmp/a.txt", 1544519753)
链接到此函数

write(path, content, modes \\ [])

查看源代码
@spec write(Path.t(), iodata(), [mode()]) :: :ok | {:error, posix()}

content 写入文件 path

如果文件不存在,则会创建该文件。 如果文件存在,则会覆盖之前的内容。 如果成功,则返回 :ok,否则返回 {:error, reason}

content 必须是 iodata(字节列表或二进制)。 为此函数设置编码没有任何效果。

警告:每次调用此函数时,都会打开一个文件描述符,并生成一个新的进程来写入文件。 因此,如果在循环中进行多次写入,则通过 File.open/2 打开文件并使用 IO 中的函数写入文件,将比多次调用此函数具有更好的性能。

常见的错误原因包括

  • :enoent - 文件名的某个组成部分不存在
  • :enotdir - 文件名的一个组件不是目录;在某些平台上,会返回 :enoent
  • :enospc - 设备上没有剩余空间
  • :eacces - 缺少写入文件或搜索父目录之一的权限
  • :eisdir - 指定的文件是一个目录

查看 File.open/2 以了解其他可用选项。

链接到此函数

write!(path, content, modes \\ [])

查看源代码
@spec write!(Path.t(), iodata(), [mode()]) :: :ok

write/3 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok

链接到此函数

write_stat(path, stat, opts \\ [])

查看源代码
@spec write_stat(Path.t(), File.Stat.t(), stat_options()) :: :ok | {:error, posix()}

将给定的 File.Stat 写回文件系统中的给定路径。返回 :ok{:error, reason}

链接到此函数

write_stat!(path, stat, opts \\ [])

查看源代码
@spec write_stat!(Path.t(), File.Stat.t(), stat_options()) :: :ok

write_stat/3 相同,但在失败的情况下会引发 File.Error 异常。否则返回 :ok