类 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.newFile.open 都为给定的文件路径创建一个 File 对象。

字符串访问模式

方法 File.newFile.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#rewindIO#pos=IO#seek 来更改文件的当前位置,以便在文件中的任何位置进行允许的读取或写入操作。

  • End only 表示只能在文件末尾进行写入,并且方法 IO#rewindIO#pos=IO#seek 不会影响写入操作。

  • Error 表示如果尝试进行不允许的读取或写入操作,则会引发异常。

现有文件的读写模式
  • 'r':

    • File 在初始时不会被截断

      f = File.new('t.txt') # => #<File:t.txt>
      f.size == 0           # => false
      
    • 文件的初始读取位置为 0

      f.pos # => 0
      
    • File 可以在任何位置进行读取;请参见 IO#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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#rewindIO#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

  • 继承自 类 IO,特别是用于创建、读取和写入文件的方法

  • 包含模块 FileTest,该模块提供了数十种其他方法。

这里,类 File 提供了对以下方面有用的方法

创建

  • ::new: 打开给定路径的文件;返回文件。

  • ::open: 与 ::new 相同,但当给出代码块时,会将文件传递给代码块,并在退出代码块时关闭文件。

  • ::link: 使用硬链接为现有文件创建新名称。

  • ::mkfifo: 返回在给定路径创建的 FIFO 文件。

  • ::symlink: 为给定文件路径创建符号链接。

查询

路径

  • ::absolute_path: 返回给定路径的绝对文件路径。

  • ::absolute_path?: 返回给定路径是否为绝对文件路径。

  • ::basename: 返回给定文件路径的最后一个组件。

  • ::dirname: 返回给定文件路径的所有组件,除了最后一个组件。

  • ::expand_path: 返回给定路径的绝对文件路径,将 ~ 扩展为主目录。

  • ::extname: 返回给定文件路径的文件扩展名。

  • ::fnmatch? (别名为 ::fnmatch): 返回给定文件路径是否与给定模式匹配。

  • ::join: 将路径组件连接成单个路径字符串。

  • ::path: 返回给定路径的字符串表示形式。

  • ::readlink: 返回给定符号链接指向的文件的路径。

  • ::realdirpath: 返回给定文件路径的真实路径,其中最后一个组件不必存在。

  • ::realpath: 返回给定文件路径的真实路径,其中所有组件都必须存在。

  • ::split: 返回一个包含两个字符串的数组:给定路径下文件的目录名称和基本名称。

  • path (别名为 to_path): 返回给定路径的字符串表示形式。

时间

  • ::atime: 返回给定文件最近访问时间的 Time 对象。

  • ::birthtime: 返回给定文件创建时间 Time 对象。

  • ::ctime: 返回给定文件元数据更改时间的 Time 对象。

  • ::mtime: 返回给定文件内容最近修改时间的 Time 对象。

  • atime: 返回 self 最近访问时间的 Time 对象。

  • birthtime: 返回 self 创建时间 Time 对象。

  • ctime: 返回 self 元数据更改时间的 Time 对象。

  • mtime: 返回 self 内容最近修改时间的 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 对象。

内容

  • ::empty? (别名为 ::zero?): 返回给定路径下的文件是否存在且为空。

  • ::size: 返回给定路径下文件的大小(字节)。

  • ::size?: 如果给定路径下没有文件或文件为空,则返回 nil;否则返回文件大小(字节)。

  • size: 返回 self 的大小(字节)。

设置

  • ::chmod: 更改给定路径下文件的权限。

  • ::chown: 更改给定路径下文件的拥有者。

  • ::lchmod: 更改给定路径中最后一个符号链接的权限。

  • ::lchown: 更改给定路径中最后一个符号链接的拥有者。

  • ::lutime: 对于每个给定的文件路径,设置路径中最后一个符号链接的访问时间和修改时间。

  • ::rename: 将一个给定路径下的文件移动到另一个给定路径。

  • ::utime: 设置给定路径下每个文件的访问时间和修改时间。

  • flock: 锁定或解锁 self

其他

  • ::truncate: 将给定文件路径下的文件截断到给定大小。

  • ::unlink (别名为 ::delete): 删除每个给定文件路径下的文件。

  • truncate: 将 self 截断到给定大小。

常量

ALT_SEPARATOR

平台特定的替代分隔符

PATH_SEPARATOR

路径列表分隔符

SEPARATOR

在路径中分隔目录部分

分隔符

在路径中分隔目录部分

公共类方法

absolute_path(file_name [, dir_string] ) → abs_file_name click to toggle source

将路径名转换为绝对路径名。 相对路径引用自进程的当前工作目录,除非给出 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);
}
absolute_path?(file_name) → true or false click to toggle source

如果 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;
}
atime(file_name) → time 点击切换源代码

返回指定文件最后访问时间,以 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);
}
basename(file_name [, suffix] ) → base_name 点击切换源代码

返回 file_name 中给定文件名(在去除尾部分隔符后)的最后一个组件。当 File::ALT_SEPARATOR 不为 nil 时,可以使用 File::SEPARATORFile::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;
}
birthtime(file_name) → time 点击切换源代码

返回指定文件的创建时间。

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);
}
blockdev?(filepath) → true or false 点击切换源代码

如果 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;
}
chardev?(filepath) → true or false 点击切换源代码

如果 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;
}
chmod(mode_int, file_name, ... ) → integer 点击切换源代码

将指定文件(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);
}
chown(owner_int, group_int, file_name, ...) → integer 点击切换源代码

将指定文件(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);
}
ctime(file_name) → time click to toggle source

返回指定文件的时间戳(文件目录信息最后修改时间,而非文件本身)。

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);
}
delete(file_name, ...) → integer click to toggle source
unlink(file_name, ...) → integer

删除指定文件,返回传递的参数数量。如果发生错误,则抛出异常。由于底层实现依赖于 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);
}
directory?(path) → true or false click to toggle source

对于给定的字符串 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;
}
dirname(file_name, level = 1) → dir_name click to toggle source

返回 file_name 中给定的文件名中的所有组件,除了最后一个组件(在首先剥离尾随分隔符之后)。当 File::ALT_SEPARATOR 不为 nil 时,文件名可以使用 File::SEPARATORFile::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);
}
zero?(file_name) → true or false click to toggle source

如果指定文件存在且大小为零,则返回 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);
}
executable?(file_name) → true or false click to toggle source

如果指定文件可被此进程的有效用户和组 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);
}
executable_real?(file_name) → true 或 false 点击切换源代码

如果指定的文件可以被当前进程的真实用户和组 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);
}
exist?(file_name) → true 或 false 点击切换源代码

如果指定的文件存在,则返回 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;
}
expand_path(file_name [, dir_string] ) → abs_file_name 点击切换源代码

将路径名转换为绝对路径名。相对路径将从进程的当前工作目录中引用,除非指定了 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);
}
extname(path) → string 点击切换源代码

返回扩展名(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?(file) → true 或 false 点击切换源代码

如果名为 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));
}
fnmatch( pattern, path, [flags] ) → (true or false) click to toggle source

如果 pathpattern 匹配,则返回 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))。

flagsFNM_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
也称为:fnmatch?
fnmatch?(pattern, path, flags = 0)
别名:fnmatch
ftype(file_name) → string click to toggle source

识别命名文件的类型;返回的字符串是“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);
}
grpowned?(file_name) → true or false click to toggle source

如果命名文件存在且调用进程的有效组 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;
}
identical?(file_1, file_2) → true or false click to toggle source

如果命名文件相同,则返回 true

file_1file_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
}
join(string, ...) → string click to toggle source

返回一个新字符串,该字符串通过使用 "/" 连接字符串形成。

File.join("usr", "mail", "gumby")   #=> "usr/mail/gumby"
static VALUE
rb_file_s_join(VALUE klass, VALUE args)
{
    return rb_file_join(args);
}
lchmod(mode_int, file_name, ...) → integer click to toggle source

等效于 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);
}
lchown(owner_int, group_int, file_name,..) → integer 点击切换源代码

等效于 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);
}
lstat(filepath) → stat 点击切换源代码

类似于 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
}
lutime(atime, mtime, file_name, ...) → integer 点击切换源代码

将每个命名文件的访问和修改时间设置为前两个参数。如果文件是符号链接,则此方法作用于链接本身,而不是其引用;对于相反的行为,请参见 File.utime。返回参数列表中的文件名数量。

static VALUE
rb_file_s_lutime(int argc, VALUE *argv, VALUE _)
{
    return utime_internal_i(argc, argv, TRUE);
}
mkfifo(file_name, mode=0666) → 0 点击切换源代码

创建名为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);
}
mtime(file_name) → time 点击切换源代码

返回命名文件的修改时间,作为 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);
}
new(path, mode = 'r', perm = 0666, **opts) → file 点击切换源代码

根据给定的mode打开给定path处的文件;创建并返回该文件的新的 File 对象。

新的 File 对象处于缓冲模式(或非同步模式),除非 filename 是一个 tty。参见 IO#flushIO#fsyncIO#fdatasyncIO#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;
}
open(path, mode = 'r', perm = 0666, **opts) → file 点击切换源代码
open(path, mode = 'r', perm = 0666, **opts) {|f| ... } → object

使用给定的参数,通过 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;
}
owned?(file_name) → true 或 false 点击切换源代码

如果指定的文件存在并且调用进程的有效用户 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());
}
path(path) → string 点击切换源代码

返回路径的字符串表示形式。

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);
}
pipe?(filepath) → true 或 false 点击切换源代码

如果 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;
}
readable?(file_name) → true 或 false 点击切换源代码

如果指定的文件可被此进程的有效用户和组 ID 读取,则返回 true。参见 eaccess(3)。

请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件不可被有效用户/组读取。

static VALUE
rb_file_readable_p(VALUE obj, VALUE fname)
{
    return RBOOL(rb_eaccess(fname, R_OK) >= 0);
}
readable_real?(file_name) → true 或 false 点击切换源代码

如果指定的文件可被此进程的真实用户和组 ID 读取,则返回 true。参见 access(3)。

请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件不可被真实用户/组读取。

static VALUE
rb_file_readable_real_p(VALUE obj, VALUE fname)
{
    return RBOOL(rb_access(fname, R_OK) >= 0);
}
realdirpath(pathname [, dir_string]) → real_pathname 点击切换源代码

返回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);
}
realpath(pathname [, dir_string]) → real_pathname 点击切换源代码

返回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);
}
rename(old_name, new_name) → 0 点击切换源代码

将给定文件重命名为新名称。如果无法重命名文件,则引发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?(file_name) → true or false 点击切换源代码

如果命名文件设置了 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?(file_name) → true or false 点击切换源代码

如果命名文件设置了 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
}
size(file_name) → integer 点击切换源代码

返回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);
}
size?(file_name) → Integer or nil 点击切换源代码

如果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);
}
socket?(filepath) → true or false 点击切换源代码

如果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;
}
split(file_name) → array 点击切换源代码

将给定字符串拆分为目录和文件组件,并将它们以两个元素数组的形式返回。另请参见File::dirnameFile::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));
}
stat(filepath) → stat 点击切换源代码

返回 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);
}
sticky?(file_name) → true 或 false 点击切换源代码

如果指定文件设置了粘滞位,则返回 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
}
truncate(file_name, integer) → 0 点击切换源代码

将文件 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() → integer 点击切换源代码
umask(integer) → integer

返回当前进程的 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);
}
utime(atime, mtime, file_name, ...) → integer 点击切换源代码

将每个指定文件的访问时间和修改时间设置为前两个参数。如果文件是符号链接,则此方法会作用于其引用对象,而不是链接本身;有关相反的行为,请参见 File.lutime。返回参数列表中的文件名数量。

static VALUE
rb_file_s_utime(int argc, VALUE *argv, VALUE _)
{
    return utime_internal_i(argc, argv, FALSE);
}
world_readable?(file_name) → integer 或 nil 点击切换源代码

如果 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;
}
world_writable?(file_name) → integer 或 nil 点击切换源代码

如果 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;
}
writable?(file_name) → true 或 false 点击切换源代码

如果指定文件可供当前进程的有效用户 ID 和组 ID 写入,则返回 true。参见 eaccess(3)。

请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件实际上不可由有效用户/组写入。

static VALUE
rb_file_writable_p(VALUE obj, VALUE fname)
{
    return RBOOL(rb_eaccess(fname, W_OK) >= 0);
}
writable_real?(file_name) → true 或 false 点击切换源代码

如果指定的文件可由该进程的真实用户和组 ID 写入,则返回 true。请参阅 access(3)。

请注意,某些操作系统级别的安全功能可能会导致此方法返回 true,即使该文件实际上不可由真实用户/组写入。

static VALUE
rb_file_writable_real_p(VALUE obj, VALUE fname)
{
    return RBOOL(rb_access(fname, W_OK) >= 0);
}
zero?(file_name) → true or false click to toggle source

如果指定文件存在且大小为零,则返回 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);
}

公共实例方法

atime → time 点击切换源代码

返回文件的最后访问时间(一个 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);
}
birthtime → time 点击切换源代码

返回文件的创建时间。

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);
}
chmod(mode_int) → 0 点击切换源代码

文件的权限位更改为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);
}
chown(owner_int, group_int ) → 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);
}
ctime → time 点击切换源代码

返回文件的更改时间(即,文件目录信息更改的时间,而不是文件本身)。

注意,在 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);
}
flock(locking_constant) → 0 或 false 点击切换源代码

根据给定的locking_constant(下表中值的按位 OR)锁定或解锁文件。

并非所有平台都可用。

如果指定了 File::LOCK_NB 并且操作会阻塞,则返回 false;否则返回 0

锁定常量
常量 锁定 效果
File::LOCK_EX 独占 一次只能有一个进程持有对 self 的独占锁定。
File::LOCK_NB 非阻塞 不阻塞;可以使用按位或运算符 | 与其他 File::LOCK_SHFile::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);
}
lstat → stat 点击切换源代码

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
}
mtime → time 点击切换源代码

返回文件的修改时间。

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);
}
size → integer 点击切换源代码

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

File.new("testfile").size   #=> 66
static VALUE
file_size(VALUE self)
{
    return OFFT2NUM(rb_file_size(self));
}
truncate(integer) → 0 点击切换源代码

文件截断为最多整数字节。文件必须以写入方式打开。并非所有平台都支持。

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);
}