非常教程

Erlang 20参考手册

核心 | kernel

file

模块

档案

模块摘要

文件接口模块。

描述

该模块提供了文件系统的接口。

在支持线程的操作系统上,文件操作可以在自己的线程中执行,从而允许其他Erlang进程与文件操作并行地继续执行。参见命令行标志+Aerl(1)

关于文件名编码,Erlang虚拟机可以以两种模式运行。当前模式可以使用函数查询native_name_encoding/0。它返回latin1utf8

latin1模式中,Erlang虚拟机不会更改文件名的编码。在utf8模式下,文件名可以包含大于255的Unicode字符,并且VM将文件名来回转换为本地文件名编码(通常是UTF-8,但是Windows上的UTF-16)。

默认模式取决于操作系统。Windows和MacOS X强制执行一致的文件名编码,因此VM使用utf8模式。

在具有透明命名的操作系统上(例如除MacOS X之外的所有Unix系统),默认情况下utf8是否终端支持UTF-8 latin1。启动时可以使用+fnl(强制latin1模式)或+fnu(强制utf8模式)覆盖默认值erts:erl

在具有透明命名的操作系统上,文件可以不一致地命名,例如,某些文件以UTF-8编码,而其他文件则以ISO Latin-1编码。引入原始文件名的概念是为了在utf8模式下运行时处理命名不一致的文件系统。

原始文件名是指定为二进制文件名。Erlang虚拟机不会在具有透明命名的系统上将指定为二进制文件的文件名转换为二进制文件。

当运行utf8模式,功能list_dir/1read_link/1永远不会返回原文件名。要返回包括原始文件名的所有文件名,请使用函数list_dir_all/1read_link_all/1

另见Notes About Raw FilenamesSTDLIB用户指南中的部分。

数据类型

deep_list() = [char() | atom() |deep_list()]

fd()

表示在raw模式。

filename() = string()

filename_all() = string() | binary()

io_device() = pid() |fd()

open/2pid()是处理I/O协议的进程。

name() = string() | atom() |deep_list()

如果VM处于Unicode文件名模式,string()并且char()允许大于255。

name_all() =

string() | atom() |deep_list()| (RawFilename :: binary())

如果VM处于Unicode文件名模式,string()并且char()允许大于255. RawFilename是不受Unicode转换限制的文件名,这意味着它可以包含不符合文件系统期望的Unicode编码的字符(即非UTF-尽管虚拟机以Unicode文件名模式启动,但仍有8个字符)。

posix() =

eacces |

eagain |

ebadf |

ebusy |

edquot |

eexist |

efault |

efbig |

eintr |

einval |

eio |

eisdir |

eloop |

emfile |

emlink |

enametoolong |

enfile |

enodev |

enoent |

enomem |

enospc |

enotblk |

enotdir |

enotsup |

enxio |

eperm |

epipe |

erofs |

espipe |

esrch |

estale |

exdev

一个由Unix中使用的POSIX错误代码以及大多数C编译器的运行时库命名的原子。

date_time() = calendar:datetime()

必须表示有效的日期和时间。

file_info() =

#file_info{size = integer() >= 0 | undefined,

type =

device |

directory |

other |

regular |

symlink |

undefined,

access =

read | write | read_write | none | undefined,

atime =

file:date_time()|

integer() >= 0 |

undefined,

mtime =

file:date_time()|

integer() >= 0 |

undefined,

ctime =

file:date_time()|

integer() >= 0 |

undefined,

mode = integer() >= 0 | undefined,

links = integer() >= 0 | undefined,

major_device = integer() >= 0 | undefined,

minor_device = integer() >= 0 | undefined,

inode = integer() >= 0 | undefined,

uid = integer() >= 0 | undefined,

gid = integer() >= 0 | undefined}

location() =

integer() |

{bof, Offset :: integer()} |

{cur, Offset :: integer()} |

{eof, Offset :: integer()} |

bof |

cur |

eof

mode() =

read |

write |

append |

exclusive |

raw |

binary |

{delayed_write,

Size :: integer() >= 0,

Delay :: integer() >= 0} |

delayed_write |

{read_ahead, Size :: integer() >= 1} |

read_ahead |

compressed |

{encoding, unicode:encoding()} |

sync

file_info_option() =

{time, local} | {time, universal} | {time, posix} | raw

出口

advise(IoDevice, Offset, Length, Advise) -> ok | {error, Reason}

类型

advise/4 可用于宣布将来以特定模式访问文件数据的意图,从而允许操作系统执行适当的优化。

在某些平台上,此功能可能不起作用。

allocate(File, Offset, Length) -> ok | {error, posix()}

类型

allocate/3可用于预分配文件的空间。

此功能仅在提供此功能的平台上成功。成功时,为文件预分配空间,但文件大小可能不会更新。这种行为取决于预分配实现。要保证文件大小已更新,请将文件截断为新大小。

change_group(Filename, Gid) -> ok | {error, Reason}

类型

更改文件组。看write_file_info/2

change_mode(Filename, Mode) -> ok | {error, Reason}

类型

更改文件的权限。看write_file_info/2

change_owner(Filename, Uid) -> ok | {error, Reason}

类型

更改文件的所有者。看write_file_info/2

change_owner(Filename, Uid, Gid) -> ok | {error, Reason}

类型

更改文件的所有者和组。参见write_file_info/2

change_time(Filename, Mtime) -> ok | {error, Reason}

类型

更改文件的修改和访问时间。参见write_file_info/2

change_time(Filename, Atime, Mtime) -> ok | {error, Reason}

类型

更改文件的修改和上次访问时间。看write_file_info/2

close(IoDevice) -> ok | {error, Reason}

类型

关闭由引用的文件IoDeviceok除了一些严重错误(如内存不足)之外,它大部分都会返回。

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

consult(Filename) -> {ok, Terms} | {error, Reason}

类型

阅读由'。'分隔的Erlang术语Filename。返回以下内容之一:

{ok, Terms}

文件已成功读取。

{error, atom()}

打开文件或读取文件时发生错误。有关典型错误代码的列表,请参阅open/2

{error, {Line, Mod, Term}}

解释文件中的Erlang术语时发生错误。要将三元素元组转换为错误的英文描述,请使用format_error/1

例子:

f.txt:  {person, "kalle", 25}.
        {person, "pelle", 30}.
1> file:consult("f.txt").
{ok,[{person,"kalle",25},{person,"pelle",30}]}

编码Filename可以通过注释来设置,如下所述epp(3)

copy(Source, Destination) -> {ok, BytesCopied} | {error, Reason}

copy(Source, Destination, ByteCount) ->

{ok, BytesCopied} | {error, Reason}

类型

ByteCountSourceto 复制字节DestinationSource例如,Destination参考文件名或IO设备open/2ByteCount默认为infinity,表示无限数量的字节。

参数Modes是可能模式的列表,请参阅open/2并默认为[]

如果同时SourceDestination指文件名,文件打开与[read, binary][write, binary]前置到他们分别列出模式,以优化复制。

如果Source引用文件名,则read在复制之前以模式列表前面的模式打开,并在完成时关闭。

如果Destination引用文件名,则write在复制之前以模式列表前面的模式打开,并在完成时关闭。

返回{ok, BytesCopied},其中BytesCopied是复制的字节数,可能小于ByteCount在源上遇到文件结尾的情况。如果操作失败,{error, Reason}则返回。

典型的错误原因:open/2如果一个文件必须打开,read/2以及write/2

datasync(IoDevice) -> ok | {error, Reason}

类型

确保操作系统(而非Erlang运行时系统)保存的任何缓冲区都写入磁盘。在很多方面它很类似,fsync但它并不更新文件的某些元数据,例如访问时间。在某些平台上,此功能不起作用。

访问数据库或日志文件的应用程序通常会写入一个微小的数据片段(例如,日志文件中的一行),然后fsync()立即调用以确保写入的数据物理存储在硬盘上。不幸的是,fsync()总是启动两个写操作:一个用于新写入的数据,另一个用于更新存储在其中的修改时间inode。如果修改时间不是事务概念的一部分,fdatasync()可用于避免不必要的inode磁盘写入操作。

只有在某些POSIX系统中才可用,此调用将导致对fsync()不提供fdatasync()系统调用的系统的调用或不起作用。

del_dir(Dir) -> ok | {error, Reason}

类型

试图删除目录Dir。该目录在被删除之前必须是空的。如果成功则返回ok

典型错误原因:

eacces

缺少搜索或写入父目录的权限Dir

eexist

目录不是空的。

enoent

目录不存在。

enotdir

组件Dir不是目录。在某些平台上,将返回enoent

einval

尝试删除当前目录。在某些平台上,将返回eacces

delete(Filename) -> ok | {error, Reason}

类型

尝试删除文件Filename.返回ok如果成功的话。

典型错误原因:

enoent

文件不存在。

eacces

对该文件或其父母之一缺少权限。

eperm

该文件是一个目录,用户不是超级用户。

enotdir

文件名的一个组件不是一个目录。在某些平台上,将返回enoent

einval

Filename具有不正确的类型,如元组。

警告

在未来的版本中,参数的错误类型Filename可能会产生异常。

eval(Filename) -> ok | {error, Reason}

类型

读取和评估由'。'分隔的Erlang表达式。(或',',表达式序列也是一个表达式)Filename。评估结果不返回;文件中的任何表达式序列都必须存在,因为它的副作用。返回以下内容之一:

ok

文件被读取和评估。

{error, atom()}

打开文件或读取文件时发生错误。有关典型错误代码的列表,请参阅open/2

{error, {Line, Mod, Term}}

解释文件中的Erlang表达式时发生错误。要将三元素元组转换为错误的英文描述,请使用format_error/1

编码Filename可以通过注释来设置,如下所述epp(3)

eval(Filename, Bindings) -> ok | {error, Reason}

类型

eval/1相同,但变量绑定Bindings用于评估。有关变量绑定的信息,请参阅erl_eval(3)

format_error(Reason) -> Chars

类型

鉴于此模块中任何函数返回的错误原因,请返回英文错误的描述性字符串。

get_cwd() -> {ok, Dir} | {error, Reason}

类型

返回{ok, Dir},其中Dir是文件服务器的当前工作目录。

在极少数情况下,这个函数可能在Unix上失败。如果当前目录的父目录不存在读取权限,则可能发生这种情况。

一个典型的错误原因是:

eacces

缺少当前目录的其中一个父项的读取权限。

get_cwd(Drive) -> {ok, Dir} | {error, Reason}

类型

返回{ok, Dir}{error, Reason},其中Dir是指定驱动器的当前工作目录。

Drive应该是“ Letter:” 的形式,例如“c:”。

{error, enotsup}在没有当前驱动器概念的平台上返回(例如,Unix)。

典型错误原因:

enotsup

操作系统没有驱动器的概念。

eacces

驱动器不存在。

einval

格式Drive无效。

list_dir(Dir) -> {ok, Filenames} | {error, Reason}

类型

列出目录中的所有文件,具有原始文件名的文件除外{ok, Filenames}如果成功则返回,否则{error, Reason}Filenames是目录中所有文件的名称列表。名称没有排序。

典型错误原因:

eacces

Dir或其某个父目录缺少搜索或写入权限。

enoent

目录不存在。

{no_translation, Filename}

Filename是以binary()ISO Latin-1编码的字符,并且VM是以参数启动的+fnue

list_dir_all(Dir) -> {ok, Filenames} | {error, Reason}

类型

列出目录中的所有文件,包括具有原始文件名的文件。{ok, Filenames}如果成功则返回,否则{error, Reason}Filenames是目录中所有文件的名称列表。名称没有排序。

典型错误原因:

eacces

Dir或其某个父目录缺少搜索或写入权限。

enoent

目录不存在。

make_dir(Dir) -> ok | {error, Reason}

类型

尝试创建目录Dir没有创建缺少父目录。如果成功则返回ok

典型错误原因:

eacces

缺少搜索或写入父目录的权限Dir

eexist

Dir已命名的文件或目录已存在。

enoent

一个组件Dir不存在。

enospc

设备上没有空间。

enotdir

组件Dir不是目录。在某些平台上,将返回enoent

make_link(Existing, New) -> ok | {error, Reason}

类型

使从硬链接ExistingNew上支撑拉杆(Unix和Windows)平台。ok如果链接成功创建,则返回此函数,否则返回{error, Reason}。在不支持链接的平台上,返回{error,enotsup}

典型错误原因:

eacces

对于缺失的父目录的读写权限ExistingNew

eexist

New已经存在了。

enotsup

在这个平台上不支持硬链接。

make_symlink(Existing, New) -> ok | {error, Reason}

类型

在支持符号链接(大多数Unix系统和Windows,从Vista开始)的平台上创建符号链接New到文件或目录ExistingExisting不需要存在。返回ok链接是否成功创建,否则返回{error, Reason}。在不支持符号链接的平台上,{error, enotsup}返回。

典型错误原因:

eacces

对于缺失的父目录的读写权限ExistingNew

eexist

New已经存在了。

enotsup

此平台不支持符号链接。

eperm

用户无权创建符号链接(SeCreateSymbolicLinkPrivilege在Windows上)。

native_name_encoding() -> latin1 | utf8

返回文件名编码模式。如果是latin1,则系统不转换文件名。如果是这样utf8,文件名被来回转换为本地文件名编码(通常是UTF-8,但是Windows上的UTF-16)。

open(File, Modes) -> {ok, IoDevice} | {error, Reason}

类型

File按照确定的模式打开文件,该模式Modes可以包含一个或多个以下选项:

read

该文件必须存在,已打开供阅读。

write

该文件被打开写入。如果它不存在,则创建它。如果该文件存在并且write未与之结合read,则该文件被截断。

append

该文件被打开写入。如果它不存在,则创建它。对打开的文件执行的每个写入操作append都发生在文件末尾。

exclusive

该文件被打开写入。如果它不存在,则创建。如果文件存在,则返回{error, eexist}

警告

此选项不保证文件系统上的排他性不O_EXCL正确,如NFS。除非您知道文件系统支持它(通常,本地文件系统是安全的),否则不要依赖此选项。

raw

允许更快地访问文件,因为不需要Erlang进程来处理文件。但是,以这种方式打开的文件具有以下限制:

  • io模块中的函数不能使用,因为它们只能与Erlang进程通信。相反,使用功能read/2read_line/1以及write/2
  • 特别是如果read_line/1要在raw文件上使用,建议将此选项与选项结合使用,{read_ahead, Size}因为面向行的I / O效率不高而不缓冲。
  • 只有打开文件的Erlang进程才能使用。
  • 远程Erlang文件服务器不能使用。运行Erlang节点的计算机必须能够访问文件系统(直接或通过NFS)。

binary

读取文件上的操作返回二进制文件,而不是列表。

{delayed_write, Size, Delay}

随后write/2调用中的数据将被缓冲,直到至少有Size字节被缓冲,或者直到最早的缓冲数据为Delay毫秒。然后将所有缓冲数据写入一个操作系统调用中。缓存的数据在write/2执行之前的其他文件操作之前也会被刷新。

此选项的目的是通过减少操作系统调用的数量来提高性能。因此,这些write/2调用的大小必须大大小于Size,并且不能被太多其他文件操作所穿插。

使用此选项时,write/2可能会过早地将调用结果报告为成功,并且如果发生写入错误,则会将错误报告为下一个文件操作的结果,该操作不会执行。

例如,在delayed_write使用多次write/2调用后,close/1可以返回{error, enospc},因为光盘上没有足够的空间用于先前写入的数据。close/1必须再次调用,因为该文件仍处于打开状态。

delayed_write

SizeDelay(和大约64 KB,2秒)的{delayed_write, Size, Delay}合理默认值相同。

{read_ahead, Size}

激活读取数据缓冲。如果read/2调用的Size字节数小于字节数,则对操作系统的读操作仍然以Size字节为单位执行。额外的数据被缓存并在随后的read/2调用中返回,随着操作系统调用次数的减少而提高性能。

read_ahead缓冲区也高度使用功能read_line/1raw模式,因此建议该选项(出于性能原因)使用该函数访问原始文件时。

如果read/2调用大小不显着小于或者甚至大于Size字节,则不会获得性能增益。

read_ahead

{read_ahead, Size}一样与合理的默认值Size(大致约64 KB)。

compressed

使读取或写入gzip压缩文件成为可能。选项compressed必须与read或组合write,但不能同时使用。请注意,使用获取的文件大小read_file_info/1可能与可以从压缩文件中读取的字节数不匹配。

{encoding, Encoding}

使文件自动转换特定(Unicode)编码中的字符。请注意,提供给still write/2或由read/2still 返回的数据是以字节为导向的; 此选项仅表示数据如何存储在磁盘文件中。

根据编码的不同,读取和写入数据的方法是首选。默认编码latin1意味着使用这个模块(file)来读写数据,因为这里提供的接口使用面向字节的数据。使用其他(Unicode)的编码使得io(3)功能get_charsget_line以及put_chars更合适的,因为它们可以与完整的Unicode范围内工作。

如果数据以io_device()无法转换为指定编码的格式发送,或者数据以无法应对数据字符范围的格式返回数据的函数读取,则会发生错误,并且文件为关闭。

允许值Encoding*

latin1

默认编码。提供给文件的字节,即在文件上write/2“按原样”写入。同样,从文件读取的字节也就是read/2“按原样”返回。如果使用模块io(3)进行写入,则文件只能处理代码点255(ISO Latin-1范围)内的Unicode字符。

unicode or utf8

在写入文件或从文件读取字符之前,字符会转换为UTF-8编码或从UTF-8编码转换。read/2只要没有存储在文件中的数据超出ISO Latin-1范围(0..255),以这种方式打开的文件就可以使用函数读取,但如果数据包含超出该范围的Unicode代码点,则会发生故障。该文件最好用Unicode识别模块中的函数读取io(3)

以任何方式写入文件的字节在存储到磁盘文件之前都会转换为UTF-8编码。

utf16 or {utf16,big}

工作就像unicode,但翻译是从大端的UTF-16而不是UTF-8进行的。

{utf16,little}

作品像unicode,但翻译是从小端UTF-16而不是UTF-8进行的。

utf32 or {utf32,big}

就像unicode,但翻译是大端UTF-32,而不是UTF-8。

{utf32,little}

就像unicode,但翻译是从小终端UTF-32,而不是UTF-8。

编码可以通过使用功能在“即时”更改为一个文件io:setopts/2。因此,可以使用latin1编码对文件进行分析,例如,将BOM放置在BOM之外,然后在进一步阅读之前将其设置为正确的编码。有关标识物料清单的功能,请参阅模块unicode(3)

此选项不允许在raw档案。

ram

File必须iodata()。返回一个fd()让模块file对内存中的数据进行操作的模块,就像它是一个文件一样。

sync

在支持它的平台上,启用POSIX O_SYNC同步I / O标志或其与平台相关的等效标志(例如,FILE_FLAG_WRITE_THROUGH在Windows上),以便写入文件块直至将数据物理写入磁盘。但是,请注意,此标志的确切语义因平台而异。例如,Linux或Windows都不保证在调用返回之前还写入所有文件元数据。要获得精确的语义,请查看平台文档的详细信息。在不支持POSIX O_SYNC或同等版本的平台上,使用该sync标志会导致open返回{error, enotsup}

返回:

{ok, IoDevice}

文件以请求模式打开。IoDevice是对文件的引用。

{error, Reason}

无法打开该文件。

IoDevice真的是处理文件的过程的PID。该过程与最初打开文件的过程相关联。如果链接的任何进程IoDevice终止,则文件关闭,进程本身终止。一个IoDevice从该调用返回可被用作一个参数,该I/O功能(见io(3))。

在以前的版本file,模式进行了指定为原子中的一个readwrite或,read_write而不是一个列表。由于向后兼容的原因,这仍然是允许的,但不能用于新代码。另请注意,read_write模式列表中不允许。

典型错误原因:

enoent

文件不存在。

eacces

缺少读取文件或搜索父目录之一的权限。

eisdir

命名文件不是常规文件。它可以是一个目录,一个FIFO,或者一个设备。

enotdir

文件名的组件不是目录。在一些平台上,enoent而是返回。

enospc

设备上没有剩余空间(如果write指定了访问权限)。

path_consult(Path, Filename) ->

{ok, Terms, FullName} | {error, Reason}

类型

搜索路径Path(目录名称列表),直到Filename找到文件。如果Filename是绝对文件名,Path则忽略。然后从文件中读取用'.'分隔的Erlang术语。

返回下列内容之一:

{ok, Terms, FullName}

文件已成功读取。FullName文件的全名。

{error, enoent}

该文件不能在任何目录中找到Path

{error, atom()}

打开文件或读取文件时发生错误。有关典型错误代码的列表,请参阅open/2

{error, {Line, Mod, Term}}

解释文件中的Erlang术语时发生错误。使用format_error/1三个元素的元组转换为错误的英文说明。

编码Filename可以通过注释来设置,如下所述epp(3)

path_eval(Path, Filename) -> {ok, FullName} | {error, Reason}

类型

搜索路径Path(目录名称列表),直到Filename找到文件。如果Filename是绝对文件名,Path则忽略。然后读取并评估由'。'分隔的Erlang表达式。(或',',表达式序列也是一个表达式)。评估结果不返回; 文件中的任何表达式序列都必须存在,因为它的副作用。

返回下列内容之一:

{ok, FullName}

该文件被读取和评估。FullName是文件的全名。

{error, enoent}

该文件不能在任何目录中找到Path

{error, atom()}

打开文件或读取文件时发生错误。有关典型错误代码的列表,请参阅open/2

{error, {Line, Mod, Term}}

解释文件中的Erlang表达式时发生错误。使用format_error/1三个元素的元组转换为错误的英文说明。

编码Filename可以通过注释来设置,如下所述epp(3)

path_open(Path, Filename, Modes) ->

{ok, IoDevice, FullName} | {error, Reason}

类型

搜索路径Path(目录名称列表),直到Filename找到文件。如果Filename是绝对文件名,Path则忽略。然后以确定的模式打开文件Modes

返回下列内容之一:

{ok, IoDevice, FullName}

该文件以请求的模式打开。IoDevice是对文件的引用,是文件FullName的全名。

{error, enoent}

该文件不能在任何目录中找到Path

{error, atom()}

无法打开该文件。

path_script(Path, Filename) ->

{ok,Value,FullName}{Error,Rational}

类型

搜索路径Path(目录名称列表),直到Filename找到文件。如果Filename是绝对文件名,Path则忽略。然后读取并评估由'。'分隔的Erlang表达式。(或',',表达式序列也是一个表达式)。

返回下列内容之一:

{ok, Value, FullName}

该文件被读取和评估。FullName是文件的全名和Value最后一个表达式的值。

{error, enoent}

该文件不能在任何目录中找到Path

{error, atom()}

打开文件或读取文件时发生错误。有关典型错误代码的列表,请参阅open/2

{error, {Line, Mod, Term}}

解释文件中的Erlang表达式时发生错误。使用format_error/1三个元素的元组转换为错误的英文说明。

编码Filename可以通过注释来设置,如下所述epp(3)

path_script(Path, Filename, Bindings) ->

{ok,Value,FullName}{Error,Rational}

类型

与评估中使用path_script/2的变量绑定相同Bindings。查看erl_eval(3)关于变量绑定。

pid2name(Pid) -> {ok, Filename} | undefined

类型

如果Pid是I/O设备,即返回的pid open/2,则此函数返回文件名,或者:

{ok, Filename}

如果此节点的文件服务器不是从属节点,则该节点的文件服务器将打开该文件(这意味着该文件Pid必须是本地pid),并且该文件未关闭。Filename是扁平字符串格式的文件名。

undefined

在所有其他情况下。

警告

此函数仅用于调试。

position(IoDevice, Location) ->

{ok, NewPosition} | {error, Reason}

类型

设置由IoDeviceto 引用的文件的位置Location{ok, NewPosition}如果成功则返回(如绝对偏移),否则返回{error, Reason}Location是以下之一:

Offset

{bof, Offset}。一样。

{bof, Offset}

绝对偏移

{cur, Offset}

从当前位置偏移。

{eof, Offset}

从文件末尾偏移。

bof | cur | eof

与上面的Offset0 相同。

请注意,偏移量以字节计算,而不是以字符计算。如果该文件是使用其它开encodinglatin1,一个字节不对应一个字符。在这样的文件中定位只能对已知的字符边界进行。也就是说,通过获取当前位置,到文件的开始/结尾或通过一些其他方式知道位于正确字符边界上的某个其他位置(通常超出文件中的字节顺序标记,它具有已知的字节大小)。

一个典型的错误原因是:

einval

要么Location是非法的,要么是文件中的负偏移。请注意,如果结果位置为负值,则结果为错误,并且在调用之后文件位置未定义。

pread(IoDevice, LocNums) -> {ok, DataL} | eof | {error, Reason}

类型

pread/3在一个操作中执行一系列操作,比一次调用一个操作更有效。根据文件的模式,或者如果所请求的位置超出文件结尾,则返回{ok, [Data, ...]}或者{error, Reason}其中每个Data对应结果pread都是列表或二进制eof文件。

由于位置被指定为字节偏移量,因此在处理encoding设置为其他内容的文件时要特别小心latin1,因为并非每个字节位置都是这样的文件上的有效字符边界。

pread(IoDevice, Location, Number) ->

pread(IoDevice, Location, Number) ->

类型

结合position/2read/2在一次操作中,这比打电话给他们一次一个更有效率。如果IoDeviceraw模式下打开,则适用一些限制:

  • Location只允许为整数。
  • 文件的当前位置在操作后未定义。

由于位置被指定为字节偏移量,因此在处理encoding设置为其他内容的文件时要特别小心latin1,因为并非每个字节位置都是这样的文件上的有效字符边界。

pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}}

类型

pwrite/3在一个操作中执行一系列操作,比一次调用一个操作更有效。返回ok{error, {N, Reason}}N失败之前成功写入的次数在哪里。

当与其他文件定位encodinglatin1,一定要小心,要设置一个正确的字符边界上的位置。有关详情,请参阅position/2

pwrite(IoDevice, Location, Bytes) -> ok | {error, Reason}

类型

结合position/2write/2在一次操作中,这比打电话给他们一次一个更有效率。如果IoDevice已在raw模式下打开,则适用一些限制:

  • Location只允许为整数。
  • 文件的当前位置在操作后未定义。

当与其他文件定位encodinglatin1,一定要小心,要设置一个正确的字符边界上的位置。有关详情,请参阅position/2

read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason}

类型

Number从引用的文件中读取字节/字符IoDevice。函数read/2pread/3read_line/1是从raw模式打开的文件读取的唯一方法(尽管它们也适用于通常打开的文件)。

对于encoding设置为其他文件的文件latin1,一个字符可以由文件中的多个字节表示。该参数Number总是表示从文件读取的字符数,而在读取Unicode文件时,文件中的位置可以移动得比这个数字多得多。

另外,如果encoding设置为其他值latin1,则read/3如果数据包含大于255的字符,则调用将失败,这就是为什么io(3)在读取此类文件时首选模块的原因。

函数返回:

{ok, Data}

如果文件是以二进制模式打开的,则以二进制方式返回读取的字节,否则返回列表中的字节。如果到达文件末尾,列表或二进制文件的长度将小于请求的字节数。

eof

如果Number>0在读取任何内容之前已达到文件结尾,则返回。

{error, Reason}

发生了一个错误。

典型错误原因:

ebadf

该文件未打开以供阅读。

{no_translation, unicode, latin1}

该文件被打开另一个encodinglatin1和文件中的数据不能被转换为面向字节的数据,该函数返回。

read_file(Filename) -> {ok, Binary} | {error, Reason}

类型

返回{ok, Binary},其中Binary是包含内容Filename{error, Reason}发生错误的二进制数据对象。

典型错误原因:

enoent

文件不存在。

eacces

缺少读取文件或搜索父目录之一的权限。

eisdir

命名文件是一个目录。

enotdir

文件名的一个组件不是一个目录。在某些平台上,enoent将返回。

enomem

文件内容没有足够的内存。

read_file_info(Filename) -> {ok, FileInfo} | {error, Reason}

read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason}

类型

检索有关文件的信息。{ok, FileInfo}如果成功则返回,否则{error, Reason}FileInfo是一个记录file_info,在内核包含文件中定义file.hrl。在调用该函数的模块中包含以下指令:

-include_lib("kernel/include/file.hrl").

时间类型中返回atimemtimectime依赖于设置在时间类型Opts :: {time, Type},如下所示:

local

返回当地时间。

universal

返回普遍时间。

posix

返回Unix时间纪元(1970-01-01 00:00 UTC)之前或之前的秒数。

默认是{time, local}

如果raw设置了该选项,则不会调用文件服务器,只会返回有关本地文件的信息。

由于文件时间存储在大多数操作系统上的POSIX时间中,因此使用选项查询文件信息会更快posix

记录file_info包含以下字段:

size = integer() >= 0

文件大小(以字节为单位)。

type = device | directory | other | regular | symlink

文件的类型。

access = read | write | read_write | none

当前系统对文件的访问。

atime =date_time()| integer() >= 0

上次文件被读取的时候。

mtime =date_time()| integer() >= 0

上次写文件的时候。

ctime =date_time()| integer() >=0

这段时间的解释取决于操作系统。在Unix上,这是最后一次该文件或被inode更改。在Windows中,这是创建时间。

mode = integer() >= 0

文件权限作为下列位值之和:

8#00400

阅读许可:所有者

8#00200

写入权限:所有者

8#00100

执行权限:所有者

8#00040

阅读权限:组

8#00020

写入权限:组

8#00010

执行权限:组

8#00004

阅读许可:其他

8#00002

写入许可:其他

8#00001

执行权限:其他

16#800

在执行时设置用户id

16#400

在执行时设置组id

在Unix平台上,可以设置上面列出的其他位。

links = integer() >= 0

指向文件的链接数(对于没有链接概念的文件系统,这总是1)。

major_device = integer() >= 0

标识文件所在的文件系统。在Windows中,数字表示一个驱动器,如下所示:0表示A :, 1表示B :,依此类推。

minor_device = integer() >= 0

只对Unix上的字符设备有效。在所有其他情况下,该字段为零。

inode = integer() >= 0

给出inode号码。在非Unix文件系统上,该字段为零。

uid = integer() >= 0

表示文件的所有者。在非Unix文件系统上,该字段为零。

gid = integer() >= 0

给出文件所有者属于的组。在非Unix文件系统上,该字段为零。

典型错误原因:

eacces

缺少文件的父目录之一的搜索权限。

enoent

文件不存在。

enotdir

文件名的一个组件不是一个目录。在某些平台上,enoent将返回。

read_line(IoDevice) -> {ok, Data} | eof | {error, Reason}

类型

从引用的文件中读取一行字节/字符IoDevice。行被定义为由换行(LF,\n)字符分隔,但任何回车符(CR,\r)后跟换行符也被视为单个LF字符(回车被忽略)。该行返回包括 LF,但不包括任何紧跟着LF的CR。这种行为与行为是一致的io:get_line/2。如果到达文件末尾没有任何LF结束最后一行,则返回一个没有结尾LF的行。

该功能可用于在raw模式下打开的文件。但是,raw如果未使用{read_ahead, Size}指定的选项打开文件,则在文件上使用它效率低下。因此,组合raw{read_ahead, Size}开口,用于生面向行的读取文本文件时,强烈建议。

如果encoding设置为其他值latin1,则read_line/1如果数据包含大于255的字符,则调用将失败,那么io(3)读取此类文件时为什么首选模块。

函数返回:

{ok, Data}

返回文件中的一行,包括尾随LF,但CRLF序列由单个LF替换(参见上文)。

如果文件以二进制模式打开,则读取的字节以二进制形式返回,否则以列表形式返回。

eof

如果在读取任何内容之前已达到文件结尾,则返回。

{error, Reason}

发生了一个错误。

典型错误原因:

ebadf

该文件未打开以供阅读。

{no_translation, unicode, latin1}

该文件被打开另一个encodinglatin1和文件上的数据不能被转换为面向字节的数据,该函数返回。

read_link(Name) -> {ok, Filename} | {error, Reason}

类型

返回{ok, Filename}if Name引用不是原始文件名的符号链接,{error, Reason}否则返回。在不支持符号链接的平台上,返回值为{error,enotsup}

典型错误原因:

einval

Name 不引用符号链接或引用的文件的名称不符合预期的编码。

enoent

文件不存在。

enotsup

此平台不支持符号链接。

read_link_all(Name) -> {ok, Filename} | {error, Reason}

类型

返回{ok, Filename}if Name引用符号链接或{error, Reason}其他。在不支持符号链接的平台上,返回值为{error,enotsup}

注意Filename可以是列表或二进制。

典型错误原因:

einval

Name不引用符号链接。

enoent

文件不存在。

enotsup

此平台不支持符号链接。

read_link_info(Name) -> {ok, FileInfo} | {error, Reason}

read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason}

类型

read_file_info/1,2除了如果Name是符号链接一样工作,关于链接的信息被返回到file_info记录中并且记录的type字段被设置为symlink

如果raw设置了该选项,则不会调用文件服务器,只会返回有关本地文件的信息。

如果Name不是符号链接,则此函数返回与结果相同的结果read_file_info/1。在不支持符号链接的平台上,此功能始终等同于read_file_info/1

rename(Source, Destination) -> ok | {error, Reason}

类型

尝试将文件重命名SourceDestination。它可以用来在目录之间移动文件(和目录),但仅仅指定目的地是不够的。目标文件名也必须指定。例如,如果bar是普通文件,foo而且baz是目录,rename("foo/bar", "baz")则会返回错误,但会rename("foo/bar", "baz/bar")成功。ok如果成功则返回。

在大多数平台上不允许重命名打开的文件(请参阅eacces下文)。

典型错误原因:

eacces

对于缺失的父目录的读写权限SourceDestination。在某些平台上,如果打开SourceDestination打开了此错误。

eexist

Destination不是一个空目录。在某些平台上,也会给出时间SourceDestination不同的类型。

einval

Source是一个根目录,或者Destination是一个子目录Source

eisdir

Destination是一个目录,但Source不是。

enoent

Source不存在。

enotdir

Source是一个目录,但Destination不是。

exdev

SourceDestination在不同的文件系统上。

script(Filename) -> {ok, Value} | {error, Reason}

类型

读取和评估由'.'分隔的Erlang表达式。(或',',表达式序列也是一个表达式)。

返回下列内容之一:

{ok, Value}

该文件被读取和评估。Value是最后一个表达式的值。

{error, atom()}

打开文件或读取文件时发生错误。有关典型错误代码的列表,请参阅open/2

{error, {Line, Mod, Term}}

解释文件中的Erlang表达式时发生错误。使用format_error/1三个元素的元组转换为错误的英文说明。

编码Filename可以通过注释来设置,如下所述epp(3)

script(Filename, Bindings) -> {ok, Value} | {error, Reason}

类型

与评估中使用script/1的变量绑定相同Bindings。查看erl_eval(3)关于变量绑定。

sendfile(Filename, Socket) ->

{ok, integer() >= 0} |

{error, inet:posix() | closed | badarg | not_owner}

类型

发送文件FilenameSocket{ok, BytesSent}如果成功则返回,否则{error, Reason}

sendfile(RawFile, Socket, Offset, Bytes, Opts) ->

{ok, integer() >= 0} |

{error, inet:posix() | closed | badarg | not_owner}

类型

发送Bytes从引用的文件RawFile的开头OffsetSocket{ok, BytesSent}如果成功则返回,否则{error, Reason}。如果在指定发送后Bytes设置为0所有数据Offset

必须使用该raw标志打开使用的文件,并且进程调用sendfile必须是套接字的控制进程。看gen_tcp:controlling_process/2

如果使用的操作系统不支持sendfile,则使用read/2gen_tcp:send/2使用的Erlang回退。

选项列表可以包含以下选项:

chunk_size

Erlang回退用于发送数据的块大小。如果使用后备,请将其设置为适合系统内存的值。默认值是20 MB。

use_threads

指示模拟器使用async线程池进行sendfile系统调用。如果您正在运行的操作系统不能正确支持非阻塞sendfile调用,这会很有用。请注意,使用async线程可能会使您的系统容易受到客户端缓慢的攻击。如果设置为true并且没有async线程可用,则该sendfile呼叫返回{error,einval}。在Erlang/OTP 17.0中引入。默认是false

set_cwd(Dir) -> ok | {error, Reason}

类型

将文件服务器的当前工作目录设置为Dir。如果成功则返回ok

模块中的函数file通常将二进制文件视为原始文件名,也就是说,即使二进制文件的编码不一致,它们也会“按原样”传递native_name_encoding()。但是,该函数期望根据返回的值对二进制文件进行编码native_name_encoding()

典型的错误原因是:

enoent

目录不存在。

enotdir

组件Dir不是目录。在某些平台上,返回enoent

eacces

缺少目录或其父目录之一的权限。

badarg

Dir 有一个不正确的类型,比如元组。

no_translation

Dir是以binary()ISO-latin-1编码的字符,并且VM使用unicode文件名编码进行操作。

警告

在未来的版本中,参数的错误类型Dir可能会产生异常。

sync(IoDevice) -> ok | {error, Reason}

类型

确保操作系统(而非Erlang运行时系统)保存的任何缓冲区都写入磁盘。在某些平台上,此功能可能不起作用。

一个典型的错误原因是:

enospc

没有足够的空间来写入文件。

truncate(IoDevice) -> ok | {error, Reason}

类型

截断IoDevice在当前位置引用的文件。如果成功则返回ok,否则{error, Reason}

write(IoDevice, Bytes) -> ok | {error, Reason}

类型

写入Bytes由引用的文件IoDevice。此功能是写入以raw模式打开的文件的唯一方式(尽管它也适用于通常打开的文件)。如果成功则返回ok,否则返回{error, Reason}

如果文件被打开并encoding设置为其他内容latin1,则写入的每个字节都可能导致将很多字节写入文件,因为根据值和UTF编码类型,字节范围0..255可以表示1到4个字节之间的任何内容。

典型错误原因:

ebadf

该文件不会被打开以进行写入。

enospc

设备上没有空间。

write_file(Filename, Bytes) -> ok | {error, Reason}

类型

iodata术语的内容写入Bytes文件Filename。如果该文件不存在,则会创建该文件。如果存在,则先前的内容被覆盖。ok如果成功则返回,否则{error, Reason}

典型错误原因:

enoent

文件名的组件不存在。

enotdir

文件名的一个组件不是一个目录。在某些平台上,将返回enoent

enospc

设备上没有空间。

eacces

缺少写入文件或搜索其中一个父目录的权限。

eisdir

命名文件是一个目录。

write_file(Filename, Bytes, Modes) -> ok | {error, Reason}

类型

write_file/2第三个参数相同,但Modes可能的模式列表请参阅open/2。该模式的标志binarywrite是隐含的,所以他们不被使用。

write_file_info(Filename, FileInfo) -> ok | {error, Reason}

write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason}

类型

更改文件信息。如果成功则返回,否ok{error, Reason}FileInfo是一个记录file_info,在内核包含文件中定义file.hrl。在调用该函数的模块中包含以下指令:

-include_lib("kernel/include/file.hrl").

时间类型设置于atime,中mtime,并ctime取决于设置的时间类型Opts :: {time, Type},如下所示:

local

解释设置为本地的时间。

universal

把它解释为宇宙时间。

posix

必须是自Unix时间纪元以来的秒数,即UTC时间1970-01-01 00:00。

默认是{time, local}

如果raw设置了该选项,则不会调用文件服务器,只会返回有关本地文件的信息。

如果指定了以下字段,则从记录中使用:

atime =date_time()| integer() >= 0

上次读取文件时。

mtime =date_time()| integer() >= 0

上次写文件的时候。

ctime =date_time()| integer() >= 0

在Unix上,为该字段指定的任何值都会被忽略(文件的“ctime”被设置为当前时间)。在Windows上,此字段是为文件设置的新创建时间。

mode = integer() >= 0

文件权限作为下列位值之和:

8#00400

阅读许可:所有者

8#00200

写入权限:所有者

8#00100

执行权限:所有者

8#00040

阅读权限:组

8#00020

写入权限:组

8#00010

执行权限:组

8#00004

阅读许可:其他

8#00002

写入许可:其他

8#00001

执行权限:其他

16#800

在执行时设置用户id

16#400

在执行时设置组id

在Unix平台上,可以设置上面列出的其他位。

uid = integer() >= 0

指示文件所有者。非Unix文件系统忽略。

gid = integer() >= 0

提供文件所有者所属的组。非Unix文件系统忽略。

典型错误原因:

eacces

缺少文件的父目录之一的搜索权限。

enoent

文件不存在。

enotdir

文件名的一个组件不是一个目录。在某些平台上,将返回enoent

POSIX错误码

  • eacces-拒绝许可
  • eagain-暂时得不到资源
  • ebadf-不良档案编号
  • ebusy - 文件忙
  • edquot - 磁盘配额超标
  • eexist - 文件已存在
  • efault - 系统调用参数中的地址不正确
  • efbig-档案太大
  • eintr - 中断系统调用
  • einval-无效论点
  • eio-I/O错误
  • eisdir-目录上的非法操作
  • eloop-符号链接太多
  • emfile-打开的档案太多
  • emlink-链接太多
  • enametoolong-文件名太长
  • enfile-文件表溢出
  • enodev-没有这种装置
  • enoent-没有这类档案或目录
  • enomem-内存不足
  • enospc-设备上没有空间
  • enotblk-需要阻止装置
  • enotdir-不是目录
  • enotsup-没有支助的行动
  • enxio-没有这种装置或地址
  • eperm-非业主
  • epipe-断管
  • erofs-只读文件系统
  • espipe-无效寻求
  • esrch-没有这种程序
  • estale-陈旧的远程文件句柄
  • exdev-跨域链接

性能

某些操作系统文件操作(例如,一个sync/1close/1一个巨大的文件)可能会阻止其调用线程几秒钟。如果这影响仿真器主线程,则响应时间不再是毫秒数量级,这取决于软实时系统中“软”的定义。

如果设备驱动程序线程池处于活动状态,则文件操作将通过这些线程完成,以便模拟器可以继续执行Erlang进程。不幸的是,由于操作系统需要额外的调度,提供文件操作的时间增加了。

如果设备驱动程序线程池被禁用或大小为0,则大文件读取和写入会被分割为很多较小的文件,这使得模拟器可以在文件操作过程中为其他进程提供服务。这与使用线程池时的效果相同,但开销较大。其他文件操作sync/1或例如close/1大文件仍然是个问题。

为了提高性能,建议使用原始文件。原始文件使用节点主机的文件系统。

对于普通文件(非原始文件),文件服务器用于查找文件,并且如果节点正在将其文件服务器作为另一个节点的文件服务器的从服务器运行,并且另一个节点在其他某台主机上运行,​​则它们可以有不同的文件系统。但是,这很少是一个问题。

普通文件实际上是一个进程,因此它可以用作I / O设备(请参阅参考资料io)。因此,将数据写入普通文件时,将数据发送到文件进程将复制所有不是二进制文件的数据。因此建议以二进制模式打开文件并编写二进制文件。如果文件在另一个节点上打开,或者文件服务器作为另一个节点的文件服务器的从服务器运行,则也会复制二进制文件。

缓存数据以减少文件操作的数量,或者说调用文件驱动程序的次数通常会提高性能。以下函数在测试时在23秒内写入4 MBytes:

create_file_slow(Name, N) when integer(N), N >= 0 ->
    {ok, FD} = file:open(Name, [raw, write, delayed_write, binary]),
    ok = create_file_slow(FD, 0, N),
    ok = ?FILE_MODULE:close(FD),
    ok.
      
create_file_slow(FD, M, M) ->
    ok;
create_file_slow(FD, M, N) ->
    ok = file:write(FD, <<M:32/unsigned>>),
    create_file_slow(FD, M+1, N).

在每次调用之前,以下功能相当的函数将1024个条目收集到128个32字节的二进制文件列表中,write/2并且在0.52秒内完成相同的工作,速度提高了44倍:

create_file(Name, N) when integer(N), N >= 0 ->
    {ok, FD} = file:open(Name, [raw, write, delayed_write, binary]),
    ok = create_file(FD, 0, N),
    ok = ?FILE_MODULE:close(FD),
    ok.
      
create_file(FD, M, M) ->
    ok;
create_file(FD, M, N) when M + 1024 =&lt; N ->
    create_file(FD, M, M + 1024, []),
    create_file(FD, M + 1024, N);
create_file(FD, M, N) ->
    create_file(FD, M, N, []).
      
create_file(FD, M, M, R) ->
    ok = file:write(FD, R);
create_file(FD, M, N0, R) when M + 8 =&lt; N0 ->
    N1  = N0-1,  N2  = N0-2,  N3  = N0-3,  N4  = N0-4, 
    N5  = N0-5,  N6  = N0-6,  N7  = N0-7,  N8  = N0-8, 
    create_file(FD, M, N8, 
                [<<N8:32/unsigned,  N7:32/unsigned, 
                   N6:32/unsigned,  N5:32/unsigned, 
                   N4:32/unsigned,  N3:32/unsigned, 
                   N2:32/unsigned,  N1:32/unsigned>> | R]);
create_file(FD, M, N0, R) ->
    N1 = N0-1,
    create_file(FD, M, N1, [<<N1:32/unsigned>> | R]).

只相信你自己的基准。如果create_file/2上面的列表长度增加,它运行速度稍快,但消耗更多的内存并导致更多的内存碎片。这对您的应用程序有多大影响是这个简单的基准测试无法预测的。

如果每个二进制文件的大小增加到64字节,它的运行速度也会稍微快一些,但代码的笨拙是两倍。在当前实现中,大于64字节的二进制文件存储在所有进程共有的内存中,并且在进程之间发送时不会被复制,而这些较小的二进制文件存储在进程堆中,并在发送时像其他任何字段一样进行复制。

所以,二进制大小为68字节,create_file/2比64字节慢30%,并导致更多的内存碎片。请注意,如果要在进程之间发送二进制文件(例如,非原始文件),结果可能会完全不同。

原始文件实际上是一个端口。将数据写入端口时,编写二进制文件列表非常有效。在写作之前不需要将深度列表弄平。在Unix主机上,尽可能使用分散输出(在一个操作中写入一组缓冲区)。通过这种方式write(FD, [Bin1, Bin2 | Bin3])写入二进制文件的内容,而不用复制数据,除了操作系统内核中的内核。

对于原始文件,pwrite/2pread/2有效地实施。文件驱动程序只对整个操作调用一次,并且列表迭代在文件驱动程序中完成。

选项delayed_writeread_aheadopen/2使文件的驱动程序缓存数据,以减少操作系统的调用次数。create_file/2在最近的例子中,这个函数没有选项需要60秒delayed_write,比2.6倍慢。

作为一个不好的例子,create_file_slow/2没有选项rawbinary并且delayed_write意味着它的调用open(Name, [write])需要1分20秒来完成,比第一个例子慢3.5倍,比优化慢150倍create_file/2

警告

如果在使用模块访问打开的文件时发生错误io,处理该文件的进程将退出。如果进程稍后尝试访问,死文件进程可能会挂起。这将在未来的版本中修复。

另见

filename(3)

Erlang 20

Erlang 是一种通用的面向并发的编程语言,可应付大规模开发活动的程序设计语言和运行环境。

主页 https://www.erlang.org/
源码 https://github.com/erlang/otp
版本 20
发布版本 20.1