类 File
File 对象是底层平台中文件的表示。
类 File 扩展了模块 FileTest
,支持诸如 File.exist?
之类的单例方法。
关于示例¶ ↑
这里许多示例使用以下变量
# English text with newlines. text = <<~EOT First line Second line Fourth line Fifth line EOT # Russian text. russian = "\u{442 435 441 442}" # => "тест" # Binary data. data = "\u9990\u9991\u9992\u9993\u9994" # Text file. File.write('t.txt', text) # File with Russian text. File.write('t.rus', russian) # File with binary data. f = File.new('t.dat', 'wb:UTF-16') f.write(data) f.close
访问模式¶ ↑
方法 File.new
和 File.open
都为给定的文件路径创建一个 File 对象。
字符串访问模式¶ ↑
方法 File.new
和 File.open
都可以接受字符串参数 mode
,它
读写模式¶ ↑
读写 mode
决定
-
文件是否在初始时被截断。
-
是否允许读取,如果允许,则
-
文件中的初始读取位置。
-
文件中的哪个位置可以进行读取。
-
-
是否允许写入,如果允许,则
-
文件中的初始写入位置。
-
文件中的哪个位置可以进行写入。
-
这些表格总结了
Read/Write Modes for Existing File |------|-----------|----------|----------|----------|-----------| | R/W | Initial | | Initial | | Initial | | Mode | Truncate? | Read | Read Pos | Write | Write Pos | |------|-----------|----------|----------|----------|-----------| | 'r' | No | Anywhere | 0 | Error | - | | 'w' | Yes | Error | - | Anywhere | 0 | | 'a' | No | Error | - | End only | End | | 'r+' | No | Anywhere | 0 | Anywhere | 0 | | 'w+' | Yes | Anywhere | 0 | Anywhere | 0 | | 'a+' | No | Anywhere | End | End only | End | |------|-----------|----------|----------|----------|-----------| Read/Write Modes for \File To Be Created |------|----------|----------|----------|-----------| | R/W | | Initial | | Initial | | Mode | Read | Read Pos | Write | Write Pos | |------|----------|----------|----------|-----------| | 'w' | Error | - | Anywhere | 0 | | 'a' | Error | - | End only | 0 | | 'w+' | Anywhere | 0 | Anywhere | 0 | | 'a+' | Anywhere | 0 | End only | End | |------|----------|----------|----------|-----------|
注意,对于不存在的文件,模式 'r'
和 'r+'
不允许(会引发异常)。
在这些表格中
-
Anywhere
表示可以使用方法IO#rewind
、IO#pos=
和IO#seek
来更改文件的当前位置,以便在文件中的任何位置进行允许的读取或写入操作。 -
End only
表示只能在文件末尾进行写入,并且方法IO#rewind
、IO#pos=
和IO#seek
不会影响写入操作。 -
Error
表示如果尝试进行不允许的读取或写入操作,则会引发异常。
现有文件的读写模式¶ ↑
-
'r'
:-
File
在初始时不会被截断f = File.new('t.txt') # => #<File:t.txt> f.size == 0 # => false
-
文件的初始读取位置为 0
f.pos # => 0
-
File
可以在任何位置进行读取;请参见IO#rewind
、IO#pos=
、IO#seek
f.readline # => "First line\n" f.readline # => "Second line\n" f.rewind f.readline # => "First line\n" f.pos = 1 f.readline # => "irst line\n" f.seek(1, :CUR) f.readline # => "econd line\n"
-
不允许写入
f.write('foo') # Raises IOError.
-
-
'w'
:-
File
在初始时会被截断path = 't.tmp' File.write(path, text) f = File.new(path, 'w') f.size == 0 # => true
-
文件的初始写入位置为 0
f.pos # => 0
-
File
可以在任何位置进行写入(即使超过文件末尾);请参见IO#rewind
、IO#pos=
、IO#seek
f.write('foo') f.flush File.read(path) # => "foo" f.pos # => 3 f.write('bar') f.flush File.read(path) # => "foobar" f.pos # => 6 f.rewind f.write('baz') f.flush File.read(path) # => "bazbar" f.pos # => 3 f.pos = 3 f.write('foo') f.flush File.read(path) # => "bazfoo" f.pos # => 6 f.seek(-3, :END) f.write('bam') f.flush File.read(path) # => "bazbam" f.pos # => 6 f.pos = 8 f.write('bah') # Zero padding as needed. f.flush File.read(path) # => "bazbam\u0000\u0000bah" f.pos # => 11
-
不允许读取
f.read # Raises IOError.
-
-
'a'
:-
File
在初始时不会被截断path = 't.tmp' File.write(path, 'foo') f = File.new(path, 'a') f.size == 0 # => false
-
文件的初始位置为 0(但会被忽略)
f.pos # => 0
-
File
只能在文件末尾写入;IO#rewind
、IO#pos=
、IO#seek
不会影响写入操作。f.write('bar') f.flush File.read(path) # => "foobar" f.write('baz') f.flush File.read(path) # => "foobarbaz" f.rewind f.write('bat') f.flush File.read(path) # => "foobarbazbat"
-
不允许读取
f.read # Raises IOError.
-
-
'r+'
:-
File
在初始时不会被截断path = 't.tmp' File.write(path, text) f = File.new(path, 'r+') f.size == 0 # => false
-
文件的初始读取位置为 0
f.pos # => 0
-
File
可以在任何位置读取或写入(即使超过文件末尾);请参阅IO#rewind
、IO#pos=
、IO#seek
。f.readline # => "First line\n" f.readline # => "Second line\n" f.rewind f.readline # => "First line\n" f.pos = 1 f.readline # => "irst line\n" f.seek(1, :CUR) f.readline # => "econd line\n" f.rewind f.write('WWW') f.flush File.read(path) # => "WWWst line\nSecond line\nFourth line\nFifth line\n" f.pos = 10 f.write('XXX') f.flush File.read(path) # => "WWWst lineXXXecond line\nFourth line\nFifth line\n" f.seek(-6, :END) # => 0 f.write('YYY') # => 3 f.flush # => #<File:t.tmp> File.read(path) # => "WWWst lineXXXecond line\nFourth line\nFifth YYYe\n" f.seek(2, :END) f.write('ZZZ') # Zero padding as needed. f.flush File.read(path) # => "WWWst lineXXXecond line\nFourth line\nFifth YYYe\n\u0000\u0000ZZZ"
-
-
'a+'
:-
File
在初始时不会被截断path = 't.tmp' File.write(path, 'foo') f = File.new(path, 'a+') f.size == 0 # => false
-
文件的初始读取位置为 0
f.pos # => 0
-
File
只能在文件末尾写入;IO#rewind
、IO#pos=
、IO#seek
不会影响写入操作。f.write('bar') f.flush File.read(path) # => "foobar" f.write('baz') f.flush File.read(path) # => "foobarbaz" f.rewind f.write('bat') f.flush File.read(path) # => "foobarbazbat"
-
File
可以在任何位置进行读取;请参见IO#rewind
、IO#pos=
、IO#seek
f.rewind f.read # => "foobarbazbat" f.pos = 3 f.read # => "barbazbat" f.seek(-3, :END) f.read # => "bat"
-
创建文件的读写模式¶ ↑
注意,对于不存在的文件,模式 'r'
和 'r+'
不允许(会引发异常)。
-
'w'
:-
文件的初始写入位置为 0
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'w') f.pos # => 0
-
File
可以在任何位置进行写入(即使超过文件末尾);请参见IO#rewind
、IO#pos=
、IO#seek
f.write('foo') f.flush File.read(path) # => "foo" f.pos # => 3 f.write('bar') f.flush File.read(path) # => "foobar" f.pos # => 6 f.rewind f.write('baz') f.flush File.read(path) # => "bazbar" f.pos # => 3 f.pos = 3 f.write('foo') f.flush File.read(path) # => "bazfoo" f.pos # => 6 f.seek(-3, :END) f.write('bam') f.flush File.read(path) # => "bazbam" f.pos # => 6 f.pos = 8 f.write('bah') # Zero padding as needed. f.flush File.read(path) # => "bazbam\u0000\u0000bah" f.pos # => 11
-
不允许读取
f.read # Raises IOError.
-
-
'a'
:-
文件的初始写入位置为 0
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'a') f.pos # => 0
-
写入仅发生在文件末尾。
f.write('foo') f.pos # => 3 f.write('bar') f.pos # => 6 f.flush File.read(path) # => "foobar" f.rewind f.write('baz') f.flush File.read(path) # => "foobarbaz"
-
不允许读取
f.read # Raises IOError.
-
-
'w+'
:-
文件的初始位置为 0。
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'w+') f.pos # => 0
-
File
可以在任何位置进行写入(即使超过文件末尾);请参见IO#rewind
、IO#pos=
、IO#seek
f.write('foo') f.flush File.read(path) # => "foo" f.pos # => 3 f.write('bar') f.flush File.read(path) # => "foobar" f.pos # => 6 f.rewind f.write('baz') f.flush File.read(path) # => "bazbar" f.pos # => 3 f.pos = 3 f.write('foo') f.flush File.read(path) # => "bazfoo" f.pos # => 6 f.seek(-3, :END) f.write('bam') f.flush File.read(path) # => "bazbam" f.pos # => 6 f.pos = 8 f.write('bah') # Zero padding as needed. f.flush File.read(path) # => "bazbam\u0000\u0000bah" f.pos # => 11
-
File
可以在任何位置读取(即使超过文件末尾);请参阅IO#rewind
、IO#pos=
、IO#seek
。f.rewind # => 0 f.read # => "bazbam\u0000\u0000bah" f.pos = 3 # => 3 f.read # => "bam\u0000\u0000bah" f.seek(-3, :END) # => 0 f.read # => "bah"
-
-
'a+'
:-
文件的初始写入位置为 0
path = 't.tmp' FileUtils.rm_f(path) f = File.new(path, 'a+') f.pos # => 0
-
写入仅发生在文件末尾。
f.write('foo') f.pos # => 3 f.write('bar') f.pos # => 6 f.flush File.read(path) # => "foobar" f.rewind f.write('baz') f.flush File.read(path) # => "foobarbaz"
-
File
可以在任何位置读取(即使超过文件末尾);请参阅IO#rewind
、IO#pos=
、IO#seek
。f.rewind f.read # => "foobarbaz" f.pos = 3 f.read # => "barbaz" f.seek(-3, :END) f.read # => "baz" f.pos = 800 f.read # => ""
-
数据模式¶ ↑
要指定数据是作为文本还是二进制数据处理,可以在上述任何字符串读写模式后添加以下任何一项。
-
't'
: 文本数据;将默认外部编码设置为Encoding::UTF_8
;在 Windows 上,启用 EOL 和 CRLF 之间的转换,并启用将0x1A
解释为文件结束标记。 -
'b'
: 二进制数据;将默认外部编码设置为Encoding::ASCII_8BIT
;在 Windows 上,抑制 EOL 和 CRLF 之间的转换,并禁用将0x1A
解释为文件结束标记。
如果两者都没有给出,则流默认为文本数据。
示例
File.new('t.txt', 'rt') File.new('t.dat', 'rb')
当指定数据模式时,不能省略读写模式,并且数据模式必须在文件创建模式之前,如果给出的话。
File.new('t.dat', 'b') # Raises an exception. File.new('t.dat', 'rxb') # Raises an exception.
文件创建模式¶ ↑
以下可以附加到上述任何可写字符串模式。
-
'x'
: 如果文件不存在,则创建文件;如果文件存在,则引发异常。
示例
File.new('t.tmp', 'wx')
当指定文件创建模式时,不能省略读写模式,并且文件创建模式必须在数据模式之后。
File.new('t.dat', 'x') # Raises an exception. File.new('t.dat', 'rxb') # Raises an exception.
整数访问模式¶ ↑
当模式为整数时,它必须是以下常量之一或更多,这些常量可以通过按位 OR 运算符 |
组合。
-
File::RDONLY
: 仅打开以供读取。 -
File::WRONLY
: 仅用于写入。 -
File::RDWR
: 用于读写。 -
File::APPEND
: 仅用于追加。
示例
File.new('t.txt', File::RDONLY) File.new('t.tmp', File::RDWR | File::CREAT | File::EXCL)
注意:Method
IO#set_encoding
不允许将模式指定为整数。
以整数形式指定的创建文件模式¶ ↑
这些常量也可以与整数模式进行按位或运算。
-
File::CREAT
: 如果文件不存在,则创建文件。 -
File::EXCL
: 如果给定File::CREAT
且文件存在,则引发异常。
以整数形式指定的数据模式¶ ↑
数据模式不能指定为整数。当流访问模式以整数形式给出时,数据模式始终为文本,而不是二进制。
请注意,虽然存在常量 File::BINARY
,但在整数流模式中设置其值不会产生任何影响;这是因为,如 File::Constants
中所述,File::BINARY
值会禁用行代码转换,但不会更改外部编码。
编码¶ ↑
以上任何字符串模式都可以指定编码 - 仅指定外部编码或同时指定外部和内部编码 - 通过在编码名称之间添加冒号来分隔。
f = File.new('t.dat', 'rb') f.external_encoding # => #<Encoding:ASCII-8BIT> f.internal_encoding # => nil f = File.new('t.dat', 'rb:UTF-16') f.external_encoding # => #<Encoding:UTF-16 (dummy)> f.internal_encoding # => nil f = File.new('t.dat', 'rb:UTF-16:UTF-16') f.external_encoding # => #<Encoding:UTF-16 (dummy)> f.internal_encoding # => #<Encoding:UTF-16> f.close
许多编码名称在数组 Encoding.name_list
中可用。
Encoding.name_list.take(3) # => ["ASCII-8BIT", "UTF-8", "US-ASCII"]
当设置外部编码时,读取的字符串在读取时会标记该编码,写入的字符串在写入时会转换为该编码。
当同时设置外部和内部编码时,读取的字符串会从外部编码转换为内部编码,写入的字符串会从内部编码转换为外部编码。有关输入和输出转码的更多详细信息,请参阅 编码。
如果外部编码为 'BOM|UTF-8'
、'BOM|UTF-16LE'
或 'BOM|UTF16-BE'
,Ruby 会在输入文档中检查 Unicode BOM,以帮助确定编码。对于 UTF-16 编码,文件打开模式必须为二进制。如果找到 BOM,则会将其剥离,并使用 BOM 中的外部编码。
请注意,BOM 样式的编码选项不区分大小写,因此 'bom|utf-8'
也是有效的。
文件权限¶ ↑
File 对象具有权限,这是一个八进制整数,表示底层平台中实际文件的权限。
请注意,文件权限与文件流(File 对象)的模式截然不同。
在 File 对象中,权限可以通过以下方式获取,其中方法 mode
尽管名称如此,但返回的是权限
f = File.new('t.txt') f.lstat.mode.to_s(8) # => "100644"
在基于 Unix 的操作系统中,三个低位八进制数字分别表示所有者 (6)、组 (4) 和世界 (4) 的权限。每个八进制数字中的三位二进制位分别表示读、写和执行权限。
因此,权限 0644
表示所有者具有读写访问权限,而组和世界具有只读访问权限。请参阅手册页 open(2) 和 chmod(2)。
对于目录,执行位的含义会发生变化:如果设置了执行位,则可以搜索目录。
权限中的高位位可能指示文件类型(普通文件、目录、管道、套接字等)以及各种其他特殊功能。
在非 Posix 操作系统上,权限可能只包含只读或读写,在这种情况下,剩余权限将类似于典型值。例如,在 Windows 上,默认权限为 0644
;唯一可以更改的是将文件设为只读,这将报告为 0444
。
对于实际在底层平台上创建文件(而不是仅仅创建 File 对象)的方法,可以指定权限
File.new('t.tmp', File::CREAT, 0644) File.new('t.tmp', File::CREAT, 0444)
也可以更改权限
f = File.new('t.tmp', File::CREAT, 0444) f.chmod(0644) f.chmod(0444)
文件常量¶ ↑
可以在模块 File::Constants
中找到用于 File 和 IO
方法的各种常量;File::Constants.constants
返回其名称的数组。
这里有什么¶ ↑
首先,其他地方有什么。类 File
这里,类 File 提供了对以下方面有用的方法
创建¶ ↑
-
::new
: 打开给定路径的文件;返回文件。 -
::link
: 使用硬链接为现有文件创建新名称。 -
::mkfifo
: 返回在给定路径创建的 FIFO 文件。 -
::symlink
: 为给定文件路径创建符号链接。
查询¶ ↑
路径
-
::absolute_path
: 返回给定路径的绝对文件路径。 -
::absolute_path?
: 返回给定路径是否为绝对文件路径。 -
::basename
: 返回给定文件路径的最后一个组件。 -
::dirname
: 返回给定文件路径的所有组件,除了最后一个组件。 -
::expand_path
: 返回给定路径的绝对文件路径,将~
扩展为主目录。 -
::extname
: 返回给定文件路径的文件扩展名。 -
::fnmatch?
(别名为::fnmatch
): 返回给定文件路径是否与给定模式匹配。 -
::join
: 将路径组件连接成单个路径字符串。 -
::path
: 返回给定路径的字符串表示形式。 -
::readlink
: 返回给定符号链接指向的文件的路径。 -
::realdirpath
: 返回给定文件路径的真实路径,其中最后一个组件不必存在。 -
::realpath
: 返回给定文件路径的真实路径,其中所有组件都必须存在。 -
::split
: 返回一个包含两个字符串的数组:给定路径下文件的目录名称和基本名称。
时间
-
::birthtime
: 返回给定文件创建时间Time
对象。
类型
-
::blockdev?
: 返回给定路径上的文件是否为块设备。 -
::chardev?
: 返回给定路径上的文件是否为字符设备。 -
::directory?
: 返回给定路径上的文件是否为目录。 -
::executable?
: 返回给定路径上的文件是否可由当前进程的有效用户和组执行。 -
::executable_real?
: 返回给定路径上的文件是否可由当前进程的真实用户和组执行。 -
::exist?
: 返回给定路径上的文件是否存在。 -
::file?
: 返回给定路径上的文件是否为普通文件。 -
::ftype
: 返回给定路径下文件的类型字符串。 -
::grpowned?
: 返回当前进程的有效组是否拥有给定路径下的文件。 -
::identical?
: 返回两个给定路径下的文件是否相同。 -
::lstat
: 返回给定路径中最后一个符号链接的File::Stat
对象。 -
::owned?
: 返回当前进程的有效用户是否拥有给定路径下的文件。 -
::pipe?
: 返回给定路径下的文件是否为管道。 -
::readable?
: 返回给定路径下的文件是否可被当前进程的有效用户和组读取。 -
::readable_real?
: 返回给定路径下的文件是否可被当前进程的真实用户和组读取。 -
::setgid?
: 返回给定路径下的文件是否设置了 setgid 位。 -
::setuid?
: 返回给定路径下的文件是否设置了 setuid 位。 -
::socket?
: 返回给定路径下的文件是否为套接字。 -
::stat
: 返回给定路径下文件的File::Stat
对象。 -
::sticky?
: 返回给定路径下的文件是否设置了粘滞位。 -
::symlink?
: 返回给定路径下的文件是否为符号链接。 -
::umask
: 返回当前进程的 umask 值。 -
::world_readable?
: 返回给定路径下的文件是否可被其他人读取。 -
::world_writable?
: 返回给定路径下的文件是否可被其他人写入。 -
::writable?
: 返回给定路径下的文件是否可被当前进程的有效用户和组写入。 -
::writable_real?
: 返回给定路径下的文件是否可被当前进程的真实用户和组写入。 -
lstat
: 返回self
路径中最后一个符号链接的File::Stat
对象。
内容
设置¶ ↑
-
::chmod
: 更改给定路径下文件的权限。 -
::chown
: 更改给定路径下文件的拥有者。 -
::lchmod
: 更改给定路径中最后一个符号链接的权限。 -
::lchown
: 更改给定路径中最后一个符号链接的拥有者。 -
::lutime
: 对于每个给定的文件路径,设置路径中最后一个符号链接的访问时间和修改时间。 -
::rename
: 将一个给定路径下的文件移动到另一个给定路径。 -
::utime
: 设置给定路径下每个文件的访问时间和修改时间。 -
flock
: 锁定或解锁self
。
其他¶ ↑
-
::truncate
: 将给定文件路径下的文件截断到给定大小。 -
truncate
: 将self
截断到给定大小。
常量
- ALT_SEPARATOR
平台特定的替代分隔符
- PATH_SEPARATOR
路径列表分隔符
- SEPARATOR
在路径中分隔目录部分
- 分隔符
在路径中分隔目录部分
公共类方法
将路径名转换为绝对路径名。 相对路径引用自进程的当前工作目录,除非给出 dir_string,在这种情况下,它将用作起点。 如果给定的路径名以“~
”开头,则不会扩展它,它将被视为普通目录名。
File.absolute_path("~oracle/bin") #=> "<relative_path>/~oracle/bin"
static VALUE s_absolute_path(int c, const VALUE * v, VALUE _) { return rb_file_s_absolute_path(c, v); }
如果 file_name
是绝对路径,则返回 true
,否则返回 false
。
File.absolute_path?("c:/foo") #=> false (on Linux), true (on Windows)
static VALUE s_absolute_path_p(VALUE klass, VALUE fname) { VALUE path = rb_get_path(fname); if (!rb_is_absolute_path(RSTRING_PTR(path))) return Qfalse; return Qtrue; }
返回指定文件最后访问时间,以 Time
对象形式表示。
file_name 可以是 IO
对象。
File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003
static VALUE rb_file_s_atime(VALUE klass, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) { int e = errno; FilePathValue(fname); rb_syserr_fail_path(e, fname); } return stat_atime(&st); }
返回 file_name 中给定文件名(在去除尾部分隔符后)的最后一个组件。当 File::ALT_SEPARATOR
不为 nil
时,可以使用 File::SEPARATOR
和 File::ALT_SEPARATOR
作为分隔符。如果给定了 suffix 且它存在于 file_name 的末尾,则将其移除。如果 suffix 为 “.*”,则会移除任何扩展名。
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" File.basename("/home/gumby/work/ruby.rb", ".*") #=> "ruby"
static VALUE rb_file_s_basename(int argc, VALUE *argv, VALUE _) { VALUE fname, fext, basename; const char *name, *p; long f, n; rb_encoding *enc; fext = Qnil; if (rb_check_arity(argc, 1, 2) == 2) { fext = argv[1]; StringValue(fext); enc = check_path_encoding(fext); } fname = argv[0]; FilePathStringValue(fname); if (NIL_P(fext) || !(enc = rb_enc_compatible(fname, fext))) { enc = rb_enc_get(fname); fext = Qnil; } if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname))) return rb_str_new_shared(fname); p = ruby_enc_find_basename(name, &f, &n, enc); if (n >= 0) { if (NIL_P(fext)) { f = n; } else { const char *fp; fp = StringValueCStr(fext); if (!(f = rmext(p, f, n, fp, RSTRING_LEN(fext), enc))) { f = n; } RB_GC_GUARD(fext); } if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname); } basename = rb_str_new(p, f); rb_enc_copy(basename, fname); return basename; }
返回指定文件的创建时间。
file_name 可以是 IO
对象。
File.birthtime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
如果平台不支持创建时间,则会抛出 NotImplementedError
异常。
RUBY_FUNC_EXPORTED VALUE rb_file_s_birthtime(VALUE klass, VALUE fname) { statx_data st; if (rb_statx(fname, &st, STATX_BTIME) < 0) { int e = errno; FilePathValue(fname); rb_syserr_fail_path(e, fname); } return statx_birthtime(&st, fname); }
如果 filepath
指向块设备,则返回 true
,否则返回 false
。
File.blockdev?('/dev/sda1') # => true File.blockdev?(File.new('t.tmp')) # => false
static VALUE rb_file_blockdev_p(VALUE obj, VALUE fname) { #ifndef S_ISBLK # ifdef S_IFBLK # define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) # else # define S_ISBLK(m) (0) /* anytime false */ # endif #endif #ifdef S_ISBLK struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; if (S_ISBLK(st.st_mode)) return Qtrue; #endif return Qfalse; }
如果 filepath
指向字符设备,则返回 true
,否则返回 false
。
File.chardev?($stdin) # => true File.chardev?('t.txt') # => false
static VALUE rb_file_chardev_p(VALUE obj, VALUE fname) { #ifndef S_ISCHR # define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #endif struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; if (S_ISCHR(st.st_mode)) return Qtrue; return Qfalse; }
将指定文件(s)的权限位更改为 mode_int 所表示的位模式。实际效果取决于操作系统(请参阅本节开头)。在 Unix 系统上,请参阅 chmod(2)
获取详细信息。返回处理的文件数量。
File.chmod(0644, "testfile", "out") #=> 2
static VALUE rb_file_s_chmod(int argc, VALUE *argv, VALUE _) { mode_t mode; apply2args(1); mode = NUM2MODET(*argv++); return apply2files(chmod_internal, argc, argv, &mode); }
将指定文件(s)的所有者和组更改为给定的数字所有者和组 ID。只有具有超级用户权限的进程才能更改文件的所有者。文件的当前所有者可以将文件的组更改为其所属的任何组。nil
或 -1 的所有者或组 ID 将被忽略。返回处理的文件数量。
File.chown(nil, 100, "testfile")
static VALUE rb_file_s_chown(int argc, VALUE *argv, VALUE _) { struct chown_args arg; apply2args(2); arg.owner = to_uid(*argv++); arg.group = to_gid(*argv++); return apply2files(chown_internal, argc, argv, &arg); }
返回指定文件的时间戳(文件目录信息最后修改时间,而非文件本身)。
file_name 可以是 IO
对象。
注意,在 Windows (NTFS) 上,返回的是创建时间(出生时间)。
File.ctime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
static VALUE rb_file_s_ctime(VALUE klass, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) { int e = errno; FilePathValue(fname); rb_syserr_fail_path(e, fname); } return stat_ctime(&st); }
删除指定文件,返回传递的参数数量。如果发生错误,则抛出异常。由于底层实现依赖于 unlink(2)
系统调用,因此抛出的异常类型取决于其错误类型(参见 linux.die.net/man/2/unlink),例如 Errno::ENOENT。
另请参见 Dir::rmdir
.
static VALUE rb_file_s_unlink(int argc, VALUE *argv, VALUE klass) { return apply2files(unlink_internal, argc, argv, 0); }
对于给定的字符串 object
,如果 path
是指向目录的字符串路径,或指向目录的符号链接,则返回 true
;否则返回 false
。
File.directory?('.') # => true File.directory?('foo') # => false File.symlink('.', 'dirlink') # => 0 File.directory?('dirlink') # => true File.symlink('t,txt', 'filelink') # => 0 File.directory?('filelink') # => false
参数 path
可以是 IO
对象。
VALUE rb_file_directory_p(VALUE obj, VALUE fname) { #ifndef S_ISDIR # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; if (S_ISDIR(st.st_mode)) return Qtrue; return Qfalse; }
返回 file_name 中给定的文件名中的所有组件,除了最后一个组件(在首先剥离尾随分隔符之后)。当 File::ALT_SEPARATOR
不为 nil
时,文件名可以使用 File::SEPARATOR
和 File::ALT_SEPARATOR
作为分隔符。
File.dirname("/home/gumby/work/ruby.rb") #=> "/home/gumby/work"
如果给定了 level
,则删除最后 level
个组件,而不仅仅是一个。
File.dirname("/home/gumby/work/ruby.rb", 2) #=> "/home/gumby" File.dirname("/home/gumby/work/ruby.rb", 4) #=> "/"
static VALUE rb_file_s_dirname(int argc, VALUE *argv, VALUE klass) { int n = 1; if ((argc = rb_check_arity(argc, 1, 2)) > 1) { n = NUM2INT(argv[1]); } return rb_file_dirname_n(argv[0], n); }
如果指定文件存在且大小为零,则返回 true
。
file_name 可以是 IO
对象。
static VALUE rb_file_zero_p(VALUE obj, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; return RBOOL(st.st_size == 0); }
如果指定文件可被此进程的有效用户和组 ID 执行,则返回 true
。参见 eaccess(3)。
Windows 不支持与读取权限分开的执行权限。在 Windows 上,只有以 .bat、.cmd、.com 或 .exe 结尾的文件才被视为可执行文件。
请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件实际上无法被有效用户/组执行。
static VALUE rb_file_executable_p(VALUE obj, VALUE fname) { return RBOOL(rb_eaccess(fname, X_OK) >= 0); }
如果指定的文件可以被当前进程的真实用户和组 ID 执行,则返回 true
。请参阅 access(3)。
Windows 不支持与读取权限分开的执行权限。在 Windows 上,只有以 .bat、.cmd、.com 或 .exe 结尾的文件才被视为可执行文件。
请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件实际上无法被真实用户/组执行。
static VALUE rb_file_executable_real_p(VALUE obj, VALUE fname) { return RBOOL(rb_access(fname, X_OK) >= 0); }
如果指定的文件存在,则返回 true
。
file_name 可以是 IO
对象。
“文件存在”意味着 stat() 或 fstat() 系统调用成功。
static VALUE rb_file_exist_p(VALUE obj, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; return Qtrue; }
将路径名转换为绝对路径名。相对路径将从进程的当前工作目录中引用,除非指定了 dir_string
,在这种情况下,它将用作起点。给定的路径名可以以“~
”开头,这将扩展到进程所有者的主目录(环境变量 HOME
必须正确设置)。“~
user”扩展到指定用户的家目录。
File.expand_path("~oracle/bin") #=> "/home/oracle/bin"
以下是一个使用 dir_string
的简单示例。
File.expand_path("ruby", "/usr/bin") #=> "/usr/bin/ruby"
以下是一个更复杂的示例,它还解析了父目录。假设我们位于 bin/mygem 中,并且想要 lib/mygem.rb 的绝对路径。
File.expand_path("../../lib/mygem.rb", __FILE__) #=> ".../path/to/project/lib/mygem.rb"
因此,它首先解析 __FILE__ 的父目录,即 bin/,然后转到父目录,即项目的根目录,并追加 lib/mygem.rb
。
static VALUE s_expand_path(int c, const VALUE * v, VALUE _) { return rb_file_s_expand_path(c, v); }
返回扩展名(path
中文件名从最后一个句点开始的部分)。
如果 path
是一个点文件,或者以句点开头,则起始句点不会被视为扩展名的开始。
如果句点是 path
中的最后一个字符,则也会返回空字符串。
在 Windows 上,尾随句点会被截断。
File.extname("test.rb") #=> ".rb" File.extname("a/b/d/test.rb") #=> ".rb" File.extname(".a/b/d/test.rb") #=> ".rb" File.extname("foo.") #=> "" on Windows File.extname("foo.") #=> "." on non-Windows File.extname("test") #=> "" File.extname(".profile") #=> "" File.extname(".profile.sh") #=> ".sh"
static VALUE rb_file_s_extname(VALUE klass, VALUE fname) { const char *name, *e; long len; VALUE extname; FilePathStringValue(fname); name = StringValueCStr(fname); len = RSTRING_LEN(fname); e = ruby_enc_find_extname(name, &len, rb_enc_get(fname)); if (len < 1) return rb_str_new(0, 0); extname = rb_str_subseq(fname, e - name, len); /* keep the dot, too! */ return extname; }
如果名为 file
的文件存在且为普通文件,则返回 true
。
file
可以是 IO
对象。
如果 file
参数是符号链接,它将解析符号链接并使用链接引用的文件。
static VALUE rb_file_file_p(VALUE obj, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; return RBOOL(S_ISREG(st.st_mode)); }
如果 path
与 pattern
匹配,则返回 true。模式不是正则表达式;而是遵循类似于 shell 文件名通配的规则。它可能包含以下元字符
*
-
匹配任何文件。可以被 glob 中的其他值限制。等效于正则表达式中的
/.*/x
。*
-
匹配所有普通文件
c*
-
匹配所有以
c
开头的文件 *c
-
匹配所有以
c
结尾的文件 *c*
-
匹配所有包含
c
的文件(包括开头或结尾)。
要匹配隐藏文件(以
.
开头),请设置 File::FNM_DOTMATCH 标志。 **
-
递归地匹配目录或扩展地匹配文件。
?
-
匹配任何一个字符。等效于正则表达式中的
/.{1}/
。 [set]
-
匹配
set
中的任何一个字符。行为与Regexp
中的字符集完全相同,包括集合否定([^a-z]
)。 \
-
转义下一个元字符。
{a,b}
-
如果启用了 File::FNM_EXTGLOB 标志,则匹配模式 a 和模式 b。行为类似于
Regexp
联合((?:a|b)
)。
flags
是 FNM_XXX
常量的按位或。Dir::glob
使用相同的 glob 模式和标志。
示例
File.fnmatch('cat', 'cat') #=> true # match entire string File.fnmatch('cat', 'category') #=> false # only match partial string File.fnmatch('c{at,ub}s', 'cats') #=> false # { } isn't supported by default File.fnmatch('c{at,ub}s', 'cats', File::FNM_EXTGLOB) #=> true # { } is supported on FNM_EXTGLOB File.fnmatch('c?t', 'cat') #=> true # '?' match only 1 character File.fnmatch('c??t', 'cat') #=> false # ditto File.fnmatch('c*', 'cats') #=> true # '*' match 0 or more characters File.fnmatch('c*t', 'c/a/b/t') #=> true # ditto File.fnmatch('ca[a-z]', 'cat') #=> true # inclusive bracket expression File.fnmatch('ca[^t]', 'cat') #=> false # exclusive bracket expression ('^' or '!') File.fnmatch('cat', 'CAT') #=> false # case sensitive File.fnmatch('cat', 'CAT', File::FNM_CASEFOLD) #=> true # case insensitive File.fnmatch('cat', 'CAT', File::FNM_SYSCASE) #=> true or false # depends on the system default File.fnmatch('?', '/', File::FNM_PATHNAME) #=> false # wildcard doesn't match '/' on FNM_PATHNAME File.fnmatch('*', '/', File::FNM_PATHNAME) #=> false # ditto File.fnmatch('[/]', '/', File::FNM_PATHNAME) #=> false # ditto File.fnmatch('\?', '?') #=> true # escaped wildcard becomes ordinary File.fnmatch('\a', 'a') #=> true # escaped ordinary remains ordinary File.fnmatch('\a', '\a', File::FNM_NOESCAPE) #=> true # FNM_NOESCAPE makes '\' ordinary File.fnmatch('[\?]', '?') #=> true # can escape inside bracket expression File.fnmatch('*', '.profile') #=> false # wildcard doesn't match leading File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true # period by default. File.fnmatch('.*', '.profile') #=> true File.fnmatch('**/*.rb', 'main.rb') #=> false File.fnmatch('**/*.rb', './main.rb') #=> false File.fnmatch('**/*.rb', 'lib/song.rb') #=> true File.fnmatch('**.rb', 'main.rb') #=> true File.fnmatch('**.rb', './main.rb') #=> false File.fnmatch('**.rb', 'lib/song.rb') #=> true File.fnmatch('*', 'dave/.profile') #=> true File.fnmatch('**/foo', 'a/b/c/foo', File::FNM_PATHNAME) #=> true File.fnmatch('**/foo', '/a/b/c/foo', File::FNM_PATHNAME) #=> true File.fnmatch('**/foo', 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true File.fnmatch('**/foo', 'a/.b/c/foo', File::FNM_PATHNAME) #=> false File.fnmatch('**/foo', 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
# File ruby_3_3_0/dir.rb, line 502 def fnmatch(pattern, path, flags = 0) end
识别命名文件的类型;返回的字符串是“file
”、“directory
”、“characterSpecial
”、“blockSpecial
”、“fifo
”、“link
”、“socket
”或“unknown
”之一。
File.ftype("testfile") #=> "file" File.ftype("/dev/tty") #=> "characterSpecial" File.ftype("/tmp/.X11-unix/X0") #=> "socket"
static VALUE rb_file_s_ftype(VALUE klass, VALUE fname) { struct stat st; FilePathValue(fname); fname = rb_str_encode_ospath(fname); if (lstat_without_gvl(StringValueCStr(fname), &st) == -1) { rb_sys_fail_path(fname); } return rb_file_ftype(&st); }
如果命名文件存在且调用进程的有效组 ID 是该文件的拥有者,则返回 true
。在 Windows 上返回 false
。
file_name 可以是 IO
对象。
static VALUE rb_file_grpowned_p(VALUE obj, VALUE fname) { #ifndef _WIN32 struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; if (rb_group_member(st.st_gid)) return Qtrue; #endif return Qfalse; }
如果命名文件相同,则返回 true
。
file_1 和 file_2 可以是 IO
对象。
open("a", "w") {} p File.identical?("a", "a") #=> true p File.identical?("a", "./a") #=> true File.link("a", "b") p File.identical?("a", "b") #=> true File.symlink("a", "c") p File.identical?("a", "c") #=> true open("d", "w") {} p File.identical?("a", "d") #=> false
static VALUE rb_file_identical_p(VALUE obj, VALUE fname1, VALUE fname2) { #ifndef _WIN32 struct stat st1, st2; if (rb_stat(fname1, &st1) < 0) return Qfalse; if (rb_stat(fname2, &st2) < 0) return Qfalse; if (st1.st_dev != st2.st_dev) return Qfalse; if (st1.st_ino != st2.st_ino) return Qfalse; return Qtrue; #else extern VALUE rb_w32_file_identical_p(VALUE, VALUE); return rb_w32_file_identical_p(fname1, fname2); #endif }
返回一个新字符串,该字符串通过使用 "/"
连接字符串形成。
File.join("usr", "mail", "gumby") #=> "usr/mail/gumby"
static VALUE rb_file_s_join(VALUE klass, VALUE args) { return rb_file_join(args); }
等效于 File::chmod
,但不跟随符号链接(因此它将更改与链接关联的权限,而不是链接引用的文件)。通常不可用。
static VALUE rb_file_s_lchmod(int argc, VALUE *argv, VALUE _) { mode_t mode; apply2args(1); mode = NUM2MODET(*argv++); return apply2files(lchmod_internal, argc, argv, &mode); }
等效于 File::chown
,但不跟随符号链接(因此它将更改与链接关联的所有者,而不是链接引用的文件)。通常不可用。返回参数列表中的文件数量。
static VALUE rb_file_s_lchown(int argc, VALUE *argv, VALUE _) { struct chown_args arg; apply2args(2); arg.owner = to_uid(*argv++); arg.group = to_gid(*argv++); return apply2files(lchown_internal, argc, argv, &arg); }
使用硬链接为现有文件创建新名称。如果new_name已存在,则不会覆盖它(引发 SystemCallError
的子类)。并非所有平台都可用。
File.link("testfile", ".testfile") #=> 0 IO.readlines(".testfile")[0] #=> "This is line one\n"
static VALUE rb_file_s_link(VALUE klass, VALUE from, VALUE to) { FilePathValue(from); FilePathValue(to); from = rb_str_encode_ospath(from); to = rb_str_encode_ospath(to); if (link(StringValueCStr(from), StringValueCStr(to)) < 0) { sys_fail2(from, to); } return INT2FIX(0); }
类似于 File::stat
,但不跟随最后一个符号链接;而是返回链接本身的 File::Stat
对象。
File.symlink('t.txt', 'symlink') File.stat('symlink').size # => 47 File.lstat('symlink').size # => 5
static VALUE rb_file_s_lstat(VALUE klass, VALUE fname) { #ifdef HAVE_LSTAT struct stat st; FilePathValue(fname); fname = rb_str_encode_ospath(fname); if (lstat_without_gvl(StringValueCStr(fname), &st) == -1) { rb_sys_fail_path(fname); } return rb_stat_new(&st); #else return rb_file_s_stat(klass, fname); #endif }
将每个命名文件的访问和修改时间设置为前两个参数。如果文件是符号链接,则此方法作用于链接本身,而不是其引用;对于相反的行为,请参见 File.utime
。返回参数列表中的文件名数量。
static VALUE rb_file_s_lutime(int argc, VALUE *argv, VALUE _) { return utime_internal_i(argc, argv, TRUE); }
创建名为file_name的 FIFO 特殊文件。mode 指定 FIFO 的权限。它以通常的方式被进程的 umask 修改:创建文件的权限为 (mode & ~umask)。
static VALUE rb_file_s_mkfifo(int argc, VALUE *argv, VALUE _) { VALUE path; struct mkfifo_arg ma; ma.mode = 0666; rb_check_arity(argc, 1, 2); if (argc > 1) { ma.mode = NUM2MODET(argv[1]); } path = argv[0]; FilePathValue(path); path = rb_str_encode_ospath(path); ma.path = RSTRING_PTR(path); if (rb_thread_call_without_gvl(nogvl_mkfifo, &ma, RUBY_UBF_IO, 0)) { rb_sys_fail_path(path); } return INT2FIX(0); }
返回命名文件的修改时间,作为 Time
对象。
file_name 可以是 IO
对象。
File.mtime("testfile") #=> Tue Apr 08 12:58:04 CDT 2003
static VALUE rb_file_s_mtime(VALUE klass, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) { int e = errno; FilePathValue(fname); rb_syserr_fail_path(e, fname); } return stat_mtime(&st); }
根据给定的mode
打开给定path
处的文件;创建并返回该文件的新的 File
对象。
新的 File
对象处于缓冲模式(或非同步模式),除非 filename
是一个 tty。参见 IO#flush
、IO#fsync
、IO#fdatasync
和 IO#sync=
。
参数 path
必须是有效的文件路径。
f = File.new('/etc/fstab') f.close f = File.new('t.txt') f.close
可选参数 mode
(默认为 'r')必须指定有效的模式;参见 访问模式
f = File.new('t.tmp', 'w') f.close f = File.new('t.tmp', File::RDONLY) f.close
可选参数 perm
(默认为 0666)必须指定有效的权限,参见 文件权限
f = File.new('t.tmp', File::CREAT, 0644) f.close f = File.new('t.tmp', File::CREAT, 0444) f.close
可选关键字参数 opts
指定
static VALUE rb_file_initialize(int argc, VALUE *argv, VALUE io) { if (RFILE(io)->fptr) { rb_raise(rb_eRuntimeError, "reinitializing File"); } if (0 < argc && argc < 3) { VALUE fd = rb_check_to_int(argv[0]); if (!NIL_P(fd)) { argv[0] = fd; return rb_io_initialize(argc, argv, io); } } rb_open_file(argc, argv, io); return io; }
使用给定的参数,通过 File.new
创建一个新的 File
对象。
如果没有给出代码块,则返回 File
对象。
如果给出代码块,则使用 File
对象调用代码块,并返回代码块的值。
static VALUE rb_io_s_open(int argc, VALUE *argv, VALUE klass) { VALUE io = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS); if (rb_block_given_p()) { return rb_ensure(rb_yield, io, io_close, io); } return io; }
如果指定的文件存在并且调用进程的有效用户 ID 是该文件的拥有者,则返回 true
。
file_name 可以是 IO
对象。
static VALUE rb_file_owned_p(VALUE obj, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; return RBOOL(st.st_uid == geteuid()); }
返回路径的字符串表示形式。
File.path(File::NULL) #=> "/dev/null" File.path(Pathname.new("/tmp")) #=> "/tmp"
static VALUE rb_file_s_path(VALUE klass, VALUE fname) { return rb_get_path(fname); }
如果 filepath
指向管道,则返回 true
,否则返回 false
。
File.mkfifo('tmp/fifo') File.pipe?('tmp/fifo') # => true File.pipe?('t.txt') # => false
static VALUE rb_file_pipe_p(VALUE obj, VALUE fname) { #ifdef S_IFIFO # ifndef S_ISFIFO # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) # endif struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; if (S_ISFIFO(st.st_mode)) return Qtrue; #endif return Qfalse; }
如果指定的文件可被此进程的有效用户和组 ID 读取,则返回 true
。参见 eaccess(3)。
请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件不可被有效用户/组读取。
static VALUE rb_file_readable_p(VALUE obj, VALUE fname) { return RBOOL(rb_eaccess(fname, R_OK) >= 0); }
如果指定的文件可被此进程的真实用户和组 ID 读取,则返回 true
。参见 access(3)。
请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件不可被真实用户/组读取。
static VALUE rb_file_readable_real_p(VALUE obj, VALUE fname) { return RBOOL(rb_access(fname, R_OK) >= 0); }
返回给定链接所引用的文件的名称。并非所有平台都可用。
File.symlink("testfile", "link2test") #=> 0 File.readlink("link2test") #=> "testfile"
static VALUE rb_file_s_readlink(VALUE klass, VALUE path) { return rb_readlink(path, rb_filesystem_encoding()); }
返回pathname在实际文件系统中的真实(绝对)路径名。真实路径名不包含符号链接或无用的点。
如果给出了dir_string,则将其用作解释相对路径名的基目录,而不是当前目录。
真实路径名的最后一个组件可能不存在。
static VALUE rb_file_s_realdirpath(int argc, VALUE *argv, VALUE klass) { VALUE basedir = (rb_check_arity(argc, 1, 2) > 1) ? argv[1] : Qnil; VALUE path = argv[0]; FilePathValue(path); return rb_realpath_internal(basedir, path, 0); }
返回pathname在实际文件系统中的真实(绝对)路径名,不包含符号链接或无用的点。
如果给出了dir_string,则将其用作解释相对路径名的基目录,而不是当前目录。
调用此方法时,路径名的所有组件都必须存在。
static VALUE rb_file_s_realpath(int argc, VALUE *argv, VALUE klass) { VALUE basedir = (rb_check_arity(argc, 1, 2) > 1) ? argv[1] : Qnil; VALUE path = argv[0]; FilePathValue(path); return rb_realpath_internal(basedir, path, 1); }
将给定文件重命名为新名称。如果无法重命名文件,则引发SystemCallError
。
File.rename("afile", "afile.bak") #=> 0
static VALUE rb_file_s_rename(VALUE klass, VALUE from, VALUE to) { struct rename_args ra; VALUE f, t; FilePathValue(from); FilePathValue(to); f = rb_str_encode_ospath(from); t = rb_str_encode_ospath(to); ra.src = StringValueCStr(f); ra.dst = StringValueCStr(t); #if defined __CYGWIN__ errno = 0; #endif if ((int)(VALUE)rb_thread_call_without_gvl(no_gvl_rename, &ra, RUBY_UBF_IO, 0) < 0) { int e = errno; #if defined DOSISH switch (e) { case EEXIST: if (chmod(ra.dst, 0666) == 0 && unlink(ra.dst) == 0 && rename(ra.src, ra.dst) == 0) return INT2FIX(0); } #endif syserr_fail2(e, from, to); } return INT2FIX(0); }
如果命名文件设置了 setgid 位,则返回true
。
file_name 可以是 IO
对象。
static VALUE rb_file_sgid_p(VALUE obj, VALUE fname) { #ifdef S_ISGID return check3rdbyte(fname, S_ISGID); #else return Qfalse; #endif }
如果命名文件设置了 setuid 位,则返回true
。
file_name 可以是 IO
对象。
static VALUE rb_file_suid_p(VALUE obj, VALUE fname) { #ifdef S_ISUID return check3rdbyte(fname, S_ISUID); #else return Qfalse; #endif }
返回file_name
的大小。
file_name 可以是 IO
对象。
static VALUE rb_file_s_size(VALUE klass, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) { int e = errno; FilePathValue(fname); rb_syserr_fail_path(e, fname); } return OFFT2NUM(st.st_size); }
如果file_name
不存在或大小为零,则返回nil
,否则返回文件的大小。
file_name 可以是 IO
对象。
static VALUE rb_file_size_p(VALUE obj, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) return Qnil; if (st.st_size == 0) return Qnil; return OFFT2NUM(st.st_size); }
如果filepath
指向套接字,则返回true
,否则返回false
。
require 'socket' File.socket?(Socket.new(:INET, :STREAM)) # => true File.socket?(File.new('t.txt')) # => false
static VALUE rb_file_socket_p(VALUE obj, VALUE fname) { #ifndef S_ISSOCK # ifdef _S_ISSOCK # define S_ISSOCK(m) _S_ISSOCK(m) # else # ifdef _S_IFSOCK # define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK) # else # ifdef S_IFSOCK # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) # endif # endif # endif #endif #ifdef S_ISSOCK struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; if (S_ISSOCK(st.st_mode)) return Qtrue; #endif return Qfalse; }
将给定字符串拆分为目录和文件组件,并将它们以两个元素数组的形式返回。另请参见File::dirname
和File::basename
。
File.split("/home/gumby/.profile") #=> ["/home/gumby", ".profile"]
static VALUE rb_file_s_split(VALUE klass, VALUE path) { FilePathStringValue(path); /* get rid of converting twice */ return rb_assoc_new(rb_file_dirname(path), rb_file_s_basename(1,&path,Qundef)); }
返回 filepath
所指向文件的 File::Stat
对象(参见 File::Stat
)。
File.stat('t.txt').class # => File::Stat
static VALUE rb_file_s_stat(VALUE klass, VALUE fname) { struct stat st; FilePathValue(fname); fname = rb_str_encode_ospath(fname); if (stat_without_gvl(RSTRING_PTR(fname), &st) < 0) { rb_sys_fail_path(fname); } return rb_stat_new(&st); }
如果指定文件设置了粘滞位,则返回 true
。
file_name 可以是 IO
对象。
static VALUE rb_file_sticky_p(VALUE obj, VALUE fname) { #ifdef S_ISVTX return check3rdbyte(fname, S_ISVTX); #else return Qfalse; #endif }
为现有文件 old_name 创建一个名为 new_name 的符号链接。在不支持符号链接的平台上会引发 NotImplemented 异常。
File.symlink("testfile", "link2test") #=> 0
static VALUE rb_file_s_symlink(VALUE klass, VALUE from, VALUE to) { FilePathValue(from); FilePathValue(to); from = rb_str_encode_ospath(from); to = rb_str_encode_ospath(to); if (symlink(StringValueCStr(from), StringValueCStr(to)) < 0) { sys_fail2(from, to); } return INT2FIX(0); }
如果 filepath
指向符号链接,则返回 true
,否则返回 false
。
symlink = File.symlink('t.txt', 'symlink') File.symlink?('symlink') # => true File.symlink?('t.txt') # => false
static VALUE rb_file_symlink_p(VALUE obj, VALUE fname) { #ifndef S_ISLNK # ifdef _S_ISLNK # define S_ISLNK(m) _S_ISLNK(m) # else # ifdef _S_IFLNK # define S_ISLNK(m) (((m) & S_IFMT) == _S_IFLNK) # else # ifdef S_IFLNK # define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) # endif # endif # endif #endif #ifdef S_ISLNK struct stat st; FilePathValue(fname); fname = rb_str_encode_ospath(fname); if (lstat_without_gvl(StringValueCStr(fname), &st) < 0) return Qfalse; if (S_ISLNK(st.st_mode)) return Qtrue; #endif return Qfalse; }
将文件 file_name 截断为最多 integer 字节长。并非所有平台都支持此功能。
f = File.new("out", "w") f.write("1234567890") #=> 10 f.close #=> nil File.truncate("out", 5) #=> 0 File.size("out") #=> 5
static VALUE rb_file_s_truncate(VALUE klass, VALUE path, VALUE len) { struct truncate_arg ta; int r; ta.pos = NUM2OFFT(len); FilePathValue(path); path = rb_str_encode_ospath(path); ta.path = StringValueCStr(path); r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_truncate, &ta, RUBY_UBF_IO, NULL); if (r < 0) rb_sys_fail_path(path); return INT2FIX(0); }
返回当前进程的 umask 值。如果提供了可选参数,则将 umask 设置为该值并返回先前值。umask 值会从默认权限中 减去,因此 umask 为 0222
会使文件对所有人只读。
File.umask(0006) #=> 18 File.umask #=> 6
static VALUE rb_file_s_umask(int argc, VALUE *argv, VALUE _) { mode_t omask = 0; switch (argc) { case 0: omask = umask(0); umask(omask); break; case 1: omask = umask(NUM2MODET(argv[0])); break; default: rb_error_arity(argc, 0, 1); } return MODET2NUM(omask); }
删除指定文件,返回传递的参数数量。如果发生错误,则抛出异常。由于底层实现依赖于 unlink(2)
系统调用,因此抛出的异常类型取决于其错误类型(参见 linux.die.net/man/2/unlink),例如 Errno::ENOENT。
另请参见 Dir::rmdir
.
static VALUE rb_file_s_unlink(int argc, VALUE *argv, VALUE klass) { return apply2files(unlink_internal, argc, argv, 0); }
将每个指定文件的访问时间和修改时间设置为前两个参数。如果文件是符号链接,则此方法会作用于其引用对象,而不是链接本身;有关相反的行为,请参见 File.lutime
。返回参数列表中的文件名数量。
static VALUE rb_file_s_utime(int argc, VALUE *argv, VALUE _) { return utime_internal_i(argc, argv, FALSE); }
如果 file_name 可供其他人读取,则返回一个整数,表示 file_name 的文件权限位。否则返回 nil
。位的含义取决于平台;在 Unix 系统上,请参见 stat(2)
。
file_name 可以是 IO
对象。
File.world_readable?("/etc/passwd") #=> 420 m = File.world_readable?("/etc/passwd") sprintf("%o", m) #=> "644"
static VALUE rb_file_world_readable_p(VALUE obj, VALUE fname) { #ifdef S_IROTH struct stat st; if (rb_stat(fname, &st) < 0) return Qnil; if ((st.st_mode & (S_IROTH)) == S_IROTH) { return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); } #endif return Qnil; }
如果 file_name 可供其他人写入,则返回一个整数,表示 file_name 的文件权限位。否则返回 nil
。位的含义取决于平台;在 Unix 系统上,请参见 stat(2)
。
file_name 可以是 IO
对象。
File.world_writable?("/tmp") #=> 511 m = File.world_writable?("/tmp") sprintf("%o", m) #=> "777"
static VALUE rb_file_world_writable_p(VALUE obj, VALUE fname) { #ifdef S_IWOTH struct stat st; if (rb_stat(fname, &st) < 0) return Qnil; if ((st.st_mode & (S_IWOTH)) == S_IWOTH) { return UINT2NUM(st.st_mode & (S_IRUGO|S_IWUGO|S_IXUGO)); } #endif return Qnil; }
如果指定文件可供当前进程的有效用户 ID 和组 ID 写入,则返回 true
。参见 eaccess(3)。
请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件实际上不可由有效用户/组写入。
static VALUE rb_file_writable_p(VALUE obj, VALUE fname) { return RBOOL(rb_eaccess(fname, W_OK) >= 0); }
如果指定的文件可由该进程的真实用户和组 ID 写入,则返回 true
。请参阅 access(3)。
请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件实际上不可由真实用户/组写入。
static VALUE rb_file_writable_real_p(VALUE obj, VALUE fname) { return RBOOL(rb_access(fname, W_OK) >= 0); }
如果指定文件存在且大小为零,则返回 true
。
file_name 可以是 IO
对象。
static VALUE rb_file_zero_p(VALUE obj, VALUE fname) { struct stat st; if (rb_stat(fname, &st) < 0) return Qfalse; return RBOOL(st.st_size == 0); }
公共实例方法
返回文件的最后访问时间(一个 Time
对象),如果文件从未被访问过,则返回纪元时间。
File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969
static VALUE rb_file_atime(VALUE obj) { rb_io_t *fptr; struct stat st; GetOpenFile(obj, fptr); if (fstat(fptr->fd, &st) == -1) { rb_sys_fail_path(fptr->pathv); } return stat_atime(&st); }
返回文件的创建时间。
File.new("testfile").birthtime #=> Wed Apr 09 08:53:14 CDT 2003
如果平台不支持创建时间,则会抛出 NotImplementedError
异常。
static VALUE rb_file_birthtime(VALUE obj) { rb_io_t *fptr; statx_data st; GetOpenFile(obj, fptr); if (fstatx_without_gvl(fptr->fd, &st, STATX_BTIME) == -1) { rb_sys_fail_path(fptr->pathv); } return statx_birthtime(&st, fptr->pathv); }
将文件的权限位更改为mode_int表示的位模式。实际效果取决于平台;在 Unix 系统上,请参阅 chmod(2)
获取详细信息。遵循符号链接。另请参阅 File#lchmod。
f = File.new("out", "w"); f.chmod(0644) #=> 0
static VALUE rb_file_chmod(VALUE obj, VALUE vmode) { rb_io_t *fptr; mode_t mode; #if !defined HAVE_FCHMOD || !HAVE_FCHMOD VALUE path; #endif mode = NUM2MODET(vmode); GetOpenFile(obj, fptr); #ifdef HAVE_FCHMOD if (fchmod(fptr->fd, mode) == -1) { if (HAVE_FCHMOD || errno != ENOSYS) rb_sys_fail_path(fptr->pathv); } else { if (!HAVE_FCHMOD) return INT2FIX(0); } #endif #if !defined HAVE_FCHMOD || !HAVE_FCHMOD if (NIL_P(fptr->pathv)) return Qnil; path = rb_str_encode_ospath(fptr->pathv); if (chmod(RSTRING_PTR(path), mode) == -1) rb_sys_fail_path(fptr->pathv); #endif return INT2FIX(0); }
将文件的所有者和组更改为给定的数字所有者和组 ID。只有具有超级用户权限的进程才能更改文件的拥有者。文件的当前拥有者可以将文件的组更改为拥有者所属的任何组。nil
或 -1 的所有者或组 ID 将被忽略。遵循符号链接。另请参阅 File#lchown。
File.new("testfile").chown(502, 1000)
static VALUE rb_file_chown(VALUE obj, VALUE owner, VALUE group) { rb_io_t *fptr; rb_uid_t o; rb_gid_t g; #ifndef HAVE_FCHOWN VALUE path; #endif o = to_uid(owner); g = to_gid(group); GetOpenFile(obj, fptr); #ifndef HAVE_FCHOWN if (NIL_P(fptr->pathv)) return Qnil; path = rb_str_encode_ospath(fptr->pathv); if (chown(RSTRING_PTR(path), o, g) == -1) rb_sys_fail_path(fptr->pathv); #else if (fchown(fptr->fd, o, g) == -1) rb_sys_fail_path(fptr->pathv); #endif return INT2FIX(0); }
返回文件的更改时间(即,文件目录信息更改的时间,而不是文件本身)。
注意,在 Windows (NTFS) 上,返回的是创建时间(出生时间)。
File.new("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003
static VALUE rb_file_ctime(VALUE obj) { rb_io_t *fptr; struct stat st; GetOpenFile(obj, fptr); if (fstat(fptr->fd, &st) == -1) { rb_sys_fail_path(fptr->pathv); } return stat_ctime(&st); }
根据给定的locking_constant
(下表中值的按位 OR)锁定或解锁文件。
并非所有平台都可用。
如果指定了 File::LOCK_NB
并且操作会阻塞,则返回 false
;否则返回 0
。
锁定常量 | ||
---|---|---|
常量 | 锁定 | 效果 |
File::LOCK_EX | 独占 | 一次只能有一个进程持有对 self 的独占锁定。 |
File::LOCK_NB | 非阻塞 | 不阻塞;可以使用按位或运算符 | 与其他 File::LOCK_SH 或 File::LOCK_EX 组合。 |
File::LOCK_SH | 共享 | 多个进程可以同时持有对 self 的共享锁定。 |
File::LOCK_UN | 解锁 | 删除此进程持有的现有锁定。 |
示例
# Update a counter using an exclusive lock. # Don't use File::WRONLY because it truncates the file. File.open('counter', File::RDWR | File::CREAT, 0644) do |f| f.flock(File::LOCK_EX) value = f.read.to_i + 1 f.rewind f.write("#{value}\n") f.flush f.truncate(f.pos) end # Read the counter using a shared lock. File.open('counter', 'r') do |f| f.flock(File::LOCK_SH) f.read end
static VALUE rb_file_flock(VALUE obj, VALUE operation) { rb_io_t *fptr; int op[2], op1; struct timeval time; op[1] = op1 = NUM2INT(operation); GetOpenFile(obj, fptr); op[0] = fptr->fd; if (fptr->mode & FMODE_WRITABLE) { rb_io_flush_raw(obj, 0); } while ((int)rb_thread_io_blocking_region(rb_thread_flock, op, fptr->fd) < 0) { int e = errno; switch (e) { case EAGAIN: case EACCES: #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif if (op1 & LOCK_NB) return Qfalse; time.tv_sec = 0; time.tv_usec = 100 * 1000; /* 0.1 sec */ rb_thread_wait_for(time); rb_io_check_closed(fptr); continue; case EINTR: #if defined(ERESTART) case ERESTART: #endif break; default: rb_syserr_fail_path(e, fptr->pathv); } } return INT2FIX(0); }
与 File#stat
相似,但不跟踪最后一个符号链接;而是返回 File::Stat
对象,表示链接本身。
File.symlink('t.txt', 'symlink') f = File.new('symlink') f.stat.size # => 47 f.lstat.size # => 11
static VALUE rb_file_lstat(VALUE obj) { #ifdef HAVE_LSTAT rb_io_t *fptr; struct stat st; VALUE path; GetOpenFile(obj, fptr); if (NIL_P(fptr->pathv)) return Qnil; path = rb_str_encode_ospath(fptr->pathv); if (lstat_without_gvl(RSTRING_PTR(path), &st) == -1) { rb_sys_fail_path(fptr->pathv); } return rb_stat_new(&st); #else return rb_io_stat(obj); #endif }
返回文件的修改时间。
File.new("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
static VALUE rb_file_mtime(VALUE obj) { rb_io_t *fptr; struct stat st; GetOpenFile(obj, fptr); if (fstat(fptr->fd, &st) == -1) { rb_sys_fail_path(fptr->pathv); } return stat_mtime(&st); }
返回文件的大小(以字节为单位)。
File.new("testfile").size #=> 66
static VALUE file_size(VALUE self) { return OFFT2NUM(rb_file_size(self)); }
将文件截断为最多整数字节。文件必须以写入方式打开。并非所有平台都支持。
f = File.new("out", "w") f.syswrite("1234567890") #=> 10 f.truncate(5) #=> 0 f.close() #=> nil File.size("out") #=> 5
static VALUE rb_file_truncate(VALUE obj, VALUE len) { rb_io_t *fptr; struct ftruncate_arg fa; fa.pos = NUM2OFFT(len); GetOpenFile(obj, fptr); if (!(fptr->mode & FMODE_WRITABLE)) { rb_raise(rb_eIOError, "not opened for writing"); } rb_io_flush_raw(obj, 0); fa.fd = fptr->fd; if ((int)rb_thread_io_blocking_region(nogvl_ftruncate, &fa, fa.fd) < 0) { rb_sys_fail_path(fptr->pathv); } return INT2FIX(0); }