网安
  • Develop
    • JAVA学习
      • 字节码
      • API开发
      • Web开发
      • 工程结构推荐
      • 创建第一个项目
      • 权限管控
      • 配置文件
      • 日志管理
      • 数据访问
      • 性能监控
      • IoC容器
      • Spring
      • Filter与Listener
      • jsp
      • MVC
      • servlet-1
      • servlet-2
      • servlet-3
      • servlet-4
      • FreeMarker
      • Thymeleaf
      • EL
      • SpEL
      • JSTL
      • 部署
      • JDBC
      • 数据库连接池
      • fastjson
      • jackson
      • XML
      • JSON
      • 序列化
      • Maven
      • 安装与使用
      • 工具
      • 爬虫
    • GO学习
      • GO
        • flag 包
        • goland 远程调试
        • GoReleaser
        • OS 包
        • time 包
        • 格式化输出
    • Lua学习
      • Lua
      • 基础语法
      • LuaJIT
      • 与系统交互
    • Pyhon
      • 基础
      • Django
      • CLI
      • miniforge
      • MockingBird
      • pdb
      • pyc
      • 装的我脑血栓要犯了
      • Python101
      • 反序列化
      • 爬虫
      • Pillow
      • 图像识别
      • flask
    • Speed-Ruby
      • 入门1
      • 入门2 对象
      • 入门3 创建命令
      • Encoding类
      • File类与Dir类
      • IO
      • Proc类
      • Time类与Date类
      • 正则
      • 错误处理与异常
      • 对象、变量和常量
      • 方法
      • 数值
      • 数组
      • 条件判断
      • 循环
      • 运算符
      • Socket编程
      • 字符串
      • 并发与线程
      • 块
      • 类和模块
      • 散列
    • Web
      • HTTP
        • Connection
        • HTTP 报文
        • Vary
      • 笔记
        • 跳转
        • 认证 & 授权
        • 同源策略(SOP)
        • 文件
    • Git 学习笔记
    • JSON
      • JSON 学习笔记
    • HTML
      • Speed-HTML
      • 语法学习
      • HTML字符实体
    • XML
      • XML 学习笔记
    • 计算机基础
      • 操作系统
      • 计算机组成
      • 算法
      • 内存
      • 字符编码
    • gnuplot 学习笔记
    • regex
  • Integrated
    • Linux
      • God-Linux
      • Secure-Linux
      • Power-Linux
      • IO模型
      • Speed-Linux
      • 发行版
      • 工具
      • 启动过程
      • 进程
      • 认证
      • 日志
      • 守护进程
      • 文件
      • 信息
      • VSFTP 配置案例
      • auditd
      • containerd
      • DNS 配置案例
      • Docker
      • Docker-Compose
      • firewalld 实验
      • gpg
      • Iptables
      • httpd
      • LAMP
      • mysql
      • nfs 配置案例
      • openssl
      • PAM
      • samba 配置案例
      • terraform
      • ufw
      • VSFTP 配置案例
    • Network
      • Speed-Net
      • Power-Net
      • SDN 笔记
      • DNS
      • TLS
    • Windows
      • Secure-Win
      • Speed-Win
      • ACL
      • LDAP
      • IPC$(Internet Process Connection)
      • PDB符号文件
      • 工作组
      • WinRM
      • 角色权限
      • 凭据
      • 签名
      • 日志
      • 认证
      • 协议
      • 信息
      • 应用
      • 组策略
      • 域
      • asp站点搭建
      • Exchange 搭建
      • Windows 故障转移集群
      • Windows 基础服务搭建
      • Windows 域搭建
      • 本地抓包
      • PowerShell 笔记
    • 容器
      • Docker
    • 数据库
      • Speed-SQL
      • Power-SQL
      • MSSQL
      • MySQL
      • Postgresql
      • Redis
      • MySQL大小写问题
      • 主键和外键
      • MySQL快速入门
      • 虚拟化
        • ESXi
        • vCenter
  • Plan
    • Mac-Plan
    • Misc-Plan
    • Team-Plan
    • Thinking-Plan
    • VM-Plan
  • Sercurity
    • Power-PenTest
    • BlueTeam
      • 安全建设
      • 分析
      • 加固
      • 取证
      • 应急
      • USB取证
      • 磁盘取证
      • 内存取证
      • ClamAV 部署
      • yara 实验
      • 安防设施搭建使用
      • ZIP明文攻击
      • 流量分析
    • Crypto
      • Crypto
        • 2020 9 G60攻防大赛
        • CTF
        • 2020 9 中能融合杯工控CTF
        • 2020 10 全国工业互联网安全技术技能大赛江苏省选拔赛
        • 2020 10 全国网络与信息安全管理职业技能大赛江苏场
        • 2020 11 I²S峰会暨工业互联网安全大赛
        • 2021 6 第二届I²S峰会暨工业互联网安全大赛
        • 2021-9-第七届工控信息安全攻防竞赛
        • 2021 9 第七届全国职工职业技能大赛某市县选拔赛
        • 2021 9 全国网络与信息安全管理职业技能大赛江苏场
        • 2021-10-G60攻防大赛
    • CTF
      • CTF
      • writeup
        • 2020 9 中能融合杯工控CTF
        • 2020 9 G60攻防大赛
        • 2020 10 全国工业互联网安全技术技能大赛江苏省选拔赛
        • 2020 10 全国网络与信息安全管理职业技能大赛江苏场
        • 2020 11 I²S峰会暨工业互联网安全大赛
        • 2021 6 第二届I²S峰会暨工业互联网安全大赛
        • 2021-9-第七届工控信息安全攻防竞赛
        • 2021 9 第七届全国职工职业技能大赛某市县选拔赛
        • 2021 9 全国网络与信息安全管理职业技能大赛江苏场
        • 2021-10-G60攻防大赛
    • ICS
      • PLC攻击
      • S7comm 相关
      • 工控协议
      • 上位机安全
      • Modbus 仿真环境搭建
      • siemens 仿真搭建实验
      • S7-300 启停实验
    • IOT
      • 无线电安全
        • RFID复制卡
        • RFID基础知识
        • WiFikiller
      • 硬件安全
        • DIY键盘嵌入指纹识别模块实验记录
        • Device-Exploits
        • HID-Digispark
        • HID-KeyboardLogger
        • HID-USBHarpoon
        • HID-USBKeyLogger
      • 固件安全
        • 固件安全
        • Dlink_DWR-932B 路由器固件分析
    • Mobile sec
      • 小程序安全
      • Android安全
    • PWN
      • SLMail溢出案例
      • PWN
    • Red Team
      • OS安全
        • Linux 安全
        • Exploits
        • NTLM中继
        • Windows 安全
        • Responder欺骗
        • Windows-LOL
      • Web_Generic
        • Top 10
          • RCE
          • Fileread
          • SQLi
          • SSRF
          • SSTI
          • Web Generic
          • XSS
          • XXE
      • Web_Tricks
        • JWT 安全
        • HTTP_request_smuggling
        • OOB
        • 绕过访问
      • 靶场
        • Hello-Java-Sec 学习
        • DVWA-WalkThrough
        • pikachu-WalkThrough
        • upload-labs-WalkThrough
        • XVWA-WalkThrough
        • XSS挑战-WalkThrough
      • 实验
        • flask
        • fastjson
        • Log4j
        • nodejs
        • Shiro
        • Spring
        • Weblogic
      • 前端攻防
      • IDOR
    • 安防设备
      • Exploits
      • Bypass 技巧
    • 后渗透
      • 权限提升
      • 后渗透
      • 权限维持
      • 实验
        • C2 实验
        • Exchange
        • 端口转发实验
        • 代理实验
        • 免杀实验
        • 隧道实验
    • 软件服务安全
      • Exploits
      • CS Exploits
      • 实验
        • Docker
        • Kubernetes
        • Mysql
        • Oracle
        • PostgreSQL
        • Redis
        • vCenter
    • 协议安全
      • Exploits
    • 信息收集
      • 端口安全
      • 空间测绘
      • 信息收集
    • 语言安全
      • 语言安全
        • 语言安全
      • GO安全
        • GO安全
        • Go代码审计
      • JAVA安全
        • JAVA安全
        • JAVA代码审计
        • JAVA反序列化
        • SpEL 注入
      • PHP安全
        • PHP安全
        • bypass_disable_function
        • bypass_open_basedir
        • phpinfo
        • PHP代码审计
        • PHP反序列化
        • PHP回调函数
        • 变量覆盖
        • POP
        • 弱类型
        • 伪协议
        • 无字母数字Webshell
      • Python安全
        • pyc反编译
        • Python安全
        • Python 代码审计
        • 沙箱逃逸
      • dotnet安全
      • JS安全
    • 云安全
      • 公有云安全
    • Reverse
      • Reverse
      • FILE
        • ELF
        • BMP
        • JPG
        • PE
        • PNG
        • ZIP
        • 文件头
      • 实验
        • PYAble
          • 2-逆运算
          • 1-基本分析
          • 3-异或
          • 4-Base64
          • 5-Base64换表
          • 6-动态调试
        • Windows
          • condrv.sys 内存损坏漏洞
    • 工具
      • Aircrack
      • BloodHound
      • Burp Suite
      • frp
      • CobaltStrike
      • Ghidra
      • fscan
      • Hashcat
      • IDA
      • merlin
      • Kali
      • Metasploit
      • Mimikatz
      • ModSecurity
      • Nmap
      • nps
      • nuclei
      • pupy
      • RedGuard
      • SET
      • sliver
      • Snort
      • Sqlmap
      • Suricata
      • Sysmon
      • uncover
      • Volatility
      • Wfuzz
      • Wireshark
      • xray
    • 安全资源
      • 靶机
        • VulnHub
          • DC
            • DC2 WalkThrough
            • DC1 WalkThrough
            • DC3 WalkThrough
            • DC4 WalkThrough
            • DC5 WalkThrough
            • DC6 WalkThrough
            • DC9 WalkThrough
            • DC8 WalkThrough
          • It's_October
            • It’s_October1 WalkThrough
          • Kioptrix
            • Kioptrix2 WalkThrough
            • Kioptrix3 WalkThrough
            • Kioptrix4 WalkThrough
            • Kioptrix5 WalkThrough
          • Mission-Pumpkin
            • PumpkinGarden-WalkThrough
            • PumpkinFestival WalkThrough
            • PumpkinRaising WalkThrough
          • Symfonos
            • symfonos1 WalkThrough
            • symfonos2 WalkThrough
            • symfonos3 WalkThrough
            • symfonos5 WalkThrough
        • Wargames
          • Bandit
            • Bandit-WalkThrough
      • 面试问题
        • 面试问题
Powered by GitBook
On this page
  • File 类与 Dir 类
  • File 类
  • 目录的操作
  • 文件名的操作
  • 与操作文件相关的库
  1. Develop
  2. Speed-Ruby

File类与Dir类

File 类与 Dir 类


  • https://www.kancloud.cn/imxieke/ruby-base/107306


File 类

File 类中实现了操作文件系统的方法。

变更文件名

  • File.rename(before, after)

    我们可以用 File.rename 方法变更文件名。

    File.rename("before.txt", "after.txt")

    还可以将文件移动到已存在的目录下,目录不存在则程序会产生错误。

    File.rename("data.txt", "backup/data.txt")

    注 File.rename 方法无法跨文件系统或者驱动器移动文件。

    如果文件不存在,或者没有适当的文件操作权限等,则文件操作失败,程序抛出异常。

    执行示例

    > irb --simple-prompt
    >> File.open("/no/such/file")
    Errno::ENOENT: No such file or directory - /no/such/file
        from (irb):1:in `initialize'
        from (irb):1:in `open'
        from (irb):1
        from /usr/bin/irb:12:in `<main>'

复制文件

只用一个 Ruby 预定义的方法是无法复制文件的。这时,我们可以利用 File.open 方法与 write 方法的组合来实现文件复制。

def copy(from, to)
  File.open(from) do |input|
    File.open(to, "w") do |output|
      output.write(input.read)
    end
  end
end

不过,由于文件复制是常用的操作,如果每次使用时都需要自己重新定义一次的话就非常麻烦。因此,我们可以通过引用 fileutils 库,使用其中的 FileUtils.cp(文件拷贝)、FileUtils.mv(文件移动)等方法来操作文件。

require "fileutils"
FileUtils.cp("data.txt", "backup/data.txt")
FileUtils.mv("data.txt", "backup/data.txt")

File.rename 不能实现的跨文件系统、驱动器的文件移动,用 FileUtils.mv 方法则可以轻松实现。

删除文件

File.delete(file)
File.unlink(file)

我们可以使用 File.delete 方法或 File.unlink 方法删除文件。

File.delete("foo")

目录的操作

Dir 类中实现了目录相关的操作方法。在详细说明前,我们先来复习一下有关目录的一些基础知识。

目录中可以存放多个文件。除了文件之外,目录中还可以存放其他目录,其他目录中又可以再存放目录……如此无限循环。通过将多个目录进行排列、嵌套,就可以轻松地管理大量的文件。

Windows 的资源管理器的左侧就是可视化的目录层次结构(树形结构)。用目录名连接 / 的方法即可指定目录中的文件。由于我们可以通过目录名指定文件的位置,因此表示文件位置的目录名就称为路径(path)或路径名。另外,我们把目录树的起点目录称为根目录(root directory),根目录只用 / 表示。

关于 Windows 的路径名

在 Windows 的命令行中,目录分隔符用的是 \。由于使用 \ 后不仅会使字符串难以读懂,而且也不能直接在 Unix 中执行同一个程序,因此还是建议大家尽量使用 /。但有一点请大家注意,像 WIN32OLE 这样使用 Windows 特有的功能时,使用 / 后可能会使程序变得无法执行。

在 Windows 中,驱动器是目录的上层文件管理单位。 一般用 1 个英文字母(盘符)表示与之相对应的驱动器,如 A: 表示软盘,C:、D:……表示硬盘。这种情况下,请读者把各驱动器当成独立的根目录来看待。例如,很明显地 C:/ 与 D:/ 表示的是不同的驱动器,但如果只写 / 的话,程序执行位置的不同,其表示的驱动器也不同,继而所表示的目录也不同。

  • Dir.pwd

  • Dir.chdir(dir)

    程序可以获取运行时所在的目录信息,即当前目录(current directory)。使用 Dir.pwd 方法获取当前目录,变更当前目录使用 Dir.chdir 方法。我们可以对 Dir.chdir 方法的参数 dir 指定相对与当前目录的相对路径,也可以指定相对于根目录的绝对路径。

    p Dir.pwd                  #=> "/usr/local/lib"
    Dir.chdir("ruby/2.0.0")    #=> 根据相对路径移动
    p Dir.pwd                  #=> "/usr/local/lib/ruby/2.0.0"
    Dir.chdir("/etc")          #=> 根据绝对路径移动
    p Dir.pwd                  #=> "/etc"

    当前目录下的文件,我们可以通过指定文件名直接打开,但如果变更了当前目录,则还需要指定目录名。

    p Dir.pwd            #=> "/usr/local/lib/ruby/2.0.0"
    io = File.open("find.rb")
                        #=> 打开"/usr/local/lib/ruby/2.0.0/find.rb"
    io.close
    Dir.chdir("../..")   # 移动到上两层的目录中
    p Dir.pwd            #=> "/usr/local/lib"
    io = File.open("ruby/2.0.0/find.rb")
                        #=> 打开"/usr/local/lib/ruby/2.0.0/find.rb"
    io.close

目录内容的读取

像介绍文件的时候一样,我们先来了解一下如何读取已存在的目录。读取目录内容的方法与读取文件的方法基本上是一样的。

  • Dir.open(path)

  • Dir.close

    与 File 类一样,Dir 类也有 open 方法与 close 方法。

    我们先试试读取 /usr/bin 目录。

    dir = Dir.open("/usr/bin")
    while name = dir.read
    p name
    end
    dir.close

    我们也可以像下面那样用 Dir#each 方法替换 while 语句部分。

    dir = Dir.open("/usr/bin")
    dir.each do |name|
    p name
    end
    dir.close

    和 File.open 同样,对 Dir.open 使用块后也可以省略 close 方法的调用。这时程序会将生成的 Dir 对象传给块变量。

    Dir.open("/usr/bin") do |dir|
    dir.each do |name|
        p name
    end
    end

    程序会输出以下内容。

    "."
    ".."
    "gnomevfs-copy"
    "updmap"
    "signver"
    "bluetooth-sendto"
    ┊
  • dir.read

    与 File 类一样,Dir 类也有 read 方法。

    执行 Dir#read 后,程序会遍历读取最先打开的目录下的内容。这里读取的内容可分为以下 4 类:

    • 表示当前目录的 .

    • 表示上级目录的 ..

    • 其他目录名

    • 文件名

    请注意 /usr/bin 与 /usr/bin/. 表示同一个目录。

    程序会操作指定目录下的所有路径。命令行参数 ARGV[0] 的路径为目录时,会对该目录下的文件进行递归处理,除此以外(文件)的情况下则调用 process_file 方法。traverse 方法会输出指定目录下的所有文件名,执行结果只显示在控制台中。

    注释中带 ※ 的代码表示忽略当前目录和上级目录,不这么做的话,就会陷入无限循环中,不断地重复处理同一个目录。

    def traverse(path)
    if File.directory?(path)  # 如果是目录
        dir = Dir.open(path)
        while name = dir.read
        next if name == "."   # ※
        next if name == ".."  # ※
        traverse(path + "/" + name)
        end
        dir.close
    else
        process_file(path)      # 处理文件
    end
    end
    def process_file(path)
    puts path                 # 输出结果
    end
     
    traverse(ARGV[0])
  • Dir.glob

    使用 Dir.glob 方法后,就可以像 shell 那样使用 * 或者 ? 等通配符(wildcard character)来取得文件名。Dir.glob 方法会将匹配到的文件名(目录名)以数组的形式返回。

    下面我们列举一些常用的匹配例子。

    获取当前目录中所有的文件名。(无法获取 Unix 中以 "." 开始的隐藏文件名)

    Dir.glob("*")

    获取当前目录中所有的隐藏文件名

    Dir.glob(".*")

    获取当前目录中扩展名为 .html 或者 .htm 的文件名。可通过数组指定多个模式。

    Dir.glob(["*.html", "*.htm"])

    模式中若没有空白,则用 %w(...) 生成字符串数组会使程序更加易懂。

    Dir.glob(%w(*.html *.htm))

    获取子目录下扩展名为 .html 或者 .htm 的文件名。

    Dir.glob(["*/*.html", "*/*.htm"])

    获取文件名为 foo.c、foo.h、foo.o 的文件。

    Dir.glob("foo.[cho]")

    获取当前目录及其子目录中所有的文件名,递归查找目录。

    Dir.glob("**/*")

    获取目录 foo 及其子目录中所有扩展名为 .html 的文件名,递归查找目录。

    Dir.glob("foo/**/*.html")

    可以像下面那样用 Dir.glob 方法改写 traverse 方法。

    def traverse(path)
      Dir.glob(["#{path}/**/*", "#{path}/**/.*"]).each do |name|
        unless File.directory?(name)
          process_file(name)
        end
      end
    end

目录的创建与删除

  • Dir.mkdir(path)

    创建新目录用 Dir.mkdir 方法。

    Dir.mkdir("temp")
  • Dir.rmdir(path)

    删除目录用 Dir.rmdir 方法。要删除的目录必须为空目录。

    Dir.rmdir("temp")

文件与目录的属性

文件与目录都有所有者、最后更新时间等属性。接下来我们就来看看如何引用和更改这些属性。

  • File.stat(path)

    通过 File.stat 方法,我们可以获取文件、目录的属性。File.stat 方法返回的是 File::Stat 类的实例。

    方法 | 返回值的含义

    • | - dev | 文件系统的编号 ino | i-node 编号 mode | 文件的属性 nlink | 链接数 uid | 文件所有者的用户 ID gid | 文件所属组的组 ID rdev | 文件系统的驱动器种类 size | 文件大小 blksize | 文件系统的块大小 blocks | 文件占用的块数量 atime | 文件的最后访问时间 mtime | 文件的最后修改时间 ctime | 文件状态的最后更改时间

    其中,除 atime 方法、mtime 方法、ctime 方法返回 Time 对象外,其他方法都返回整数值。

    通过 uid 方法与 gid 方法获取对应的用户 ID 与组 ID 时,需要用到 Etc 模块。我们可以通过 require 'etc' 来引用 Etc 模块。

    mswin32 版的 Ruby 不能使用 Etc 模块。

    下面是显示文件 /usr/local/bin/ruby 的用户名与组名的程序:

    require 'etc'
     
    st = File.stat("/usr/local/bin/ruby")
    pw = Etc.getpwuid(st.uid)
    p pw.name    #=> "root"
    gr = Etc.getgrgid(st.gid)
    p gr.name    #=> "wheel"
  • File.ctime(path)

  • File.mtime(path)

  • File.atime(path)

    这三个方法的执行结果与实例方法 File::Stat#ctime、File::Stat#mtime、File::Stat#atime 是一样的。需要同时使用其中的两个以上的方法时,选择实例方法会更加有效率。

  • File.utime(atime, mtime, path)

    改变文件属性中的最后访问时间 atime、最后修改时间 mtime。时间可以用整数值或者 Time 对象指定。另外,同时还可以指定多个路径。下面是修改文件 foo 的最后访问时间以及最后修改时间的程序。通过 Time.now 方法创建表示当前时间的 Time 对象,然后将时间设为当前时间减去 100 秒。

    filename = "foo"
    File.open(filename, "w").close    # 创建文件后关闭
     
    st = File.stat(filename)
    p st.ctime    #=> 2013-03-30 04:20:01 +0900
    p st.mtime    #=> 2013-03-30 04:20:01 +0900
    p st.atime    #=> 2013-03-30 04:20:01 +0900
     
    File.utime(Time.now-100, Time.now-100, filename)
    st = File.stat(filename)
    p st.ctime    #=> 2013-03-30 04:20:01 +0900
    p st.mtime    #=> 2013-03-30 04:18:21 +0900
    p st.atime    #=> 2013-03-30 04:18:21 +0900
  • File.chmod(mode, path)

    修改文件 path 的访问权限(permission)。mode 的值为整数值,表示新的访问权限值。同时还能指定多个路径。

    备注 在 Windows 中只有文件的所有者才有写入的权限。执行权限则是由扩展名(.bat、.exe 等)决定的。

    访问权限是用于表示是否可以进行执行、读取、写入操作的 3 位数。访问权限又细分为所有者、所属组、其他三种权限,因此完整的访问权限用 9 位数表示。

    以下程序是将文件 test.txt 的访问权限设为 0755(所有者拥有所有权限,其他用户为只读权限):

    File.chmod(0755, "test.txt")

    像对现在的访问权限追加执行权限这样追加特定运算时,需要对从 File.stat 方法得到的访问权限位进行追加位的位运算,然后再用计算后的新值重新设定。使用按位或运算追加权限位。

    rb_file = "test.rb"
    st = File.stat(rb_file)
    File.chmod(st.mode | 0111, rb_file)  # 追加执行权限
  • File.chown(owner, group, path)

    改变文件 path 的所有者。owner 表示新的所有者的用户 ID,group 表示新的所属组 ID。同时也可以指定多个路径。执行这个命令需要有管理员的权限。

    备注 Windows 中虽然也提供了这个方法,但调用时什么都不会发生。

FileTest 模块

FileTest 模块中的方法用于检查文件的属性。该模块可以在 include 后使用,也可以直接作为模块函数使用。其中的方法也可以作为 File 类的类方法使用。

方法 | 返回值

  • | - exist?(path) | path 若存在则返回 true file?(path) | path 若是文件则返回 true directory?(path) | path 若是目录则返回 true owned?(path) | path 的所有者与执行用户一样则返回 true grpowned?(path) | path 的所属组与执行用户的所属组一样则返回 true readable?(path) | path 可读取则返回 true writable?(path) | path 可写则返回 true executable?(path) | path 可执行则返回 true size(path) | 返回 path 的大小 size?(path) | path 的大小比 0 大则返回 true ,大小为 0 或者文件不存在则返回 nil zero?(path) | path 的大小为 0 则返回 true

文件名的操作

操作文件时,我们常常需要操作文件名。Ruby 为我们提供了从路径名中获取目录名、文件名的方法、以及相反的由目录名和文件名生成路径名的方法。

  • File.basename(path[, suffix])

    返回路径 path 中最后一个 "/" 以后的部分。如果指定了扩展名 suffix,则会去除返回值中扩展名的部分。在从路径中获取文件名的时候使用本方法。

    p File.basename("/usr/local/bin/ruby")    #=> "ruby"
    p File.basename("src/ruby/file.c", ".c")  #=> "file"
    p File.basename("file.c")                 #=> "file"
  • File.dirname(path)

    返回路径 path 中最后一个 "/" 之前的内容。路径不包含 "/" 时则返回 "."。在从路径中获取目录名的时候使用本方法。

    p File.dirname("/usr/local/bin/ruby")    #=> "/usr/local/bin"
    p File.dirname("ruby")                   #=> "."
    p File.dirname("/")                      #=> "/"
  • File.extname(path)

    返回路径 path 中 basename 方法返回结果中的扩展名。没有扩展名或者以 "." 开头的文件名时则返回空字符串。

    p File.extname("helloruby.rb")            #=> ".rb"
    p File.extname("ruby-2.0.0-p0.tar.gz")    #=> ".gz"
    p File.extname("img/foo.png")             #=> ".png"
    p File.extname("/usr/local/bin/ruby")     #=> ""
    p File.extname("~/.zshrc")                #=> ""
    p File.extname("/etc/init.d/ssh")         #=> ""
  • File.split(path)

    将路径 path 分割为目录名与文件名两部分,并以数组形式返回。在知道返回值的数量时,使用多重赋值会方便得多。

    p File.split("/usr/local/bin/ruby")
                            #=> ["/usr/local/bin", "ruby"]
    p File.split("ruby")    #=> [".", "ruby"]
    p File.split("/")       #=> ["/", ""]
     
    dir, base = File.split("/usr/local/bin/ruby")
    p dir                   #=> "/usr/local/bin"
    p base                  #=> "ruby"
  • File.join(name1[, name2, …])

    用 File::SEPARATOR 连接参数指定的字符串。File::SEPARATOR 的默认设值为 "/" 。

    p File.join("/usr/bin", "ruby")    #=> "/usr/bin/ruby"
    p File.join(".", "ruby")           #=> "./ruby"
  • File.expand_path(path[, default_dir])

    根据目录名 default_dir,将相对路径 path 转换为绝对路径。不指定 default_dir 时,则根据当前目录转换。

    p Dir.pwd                            #=> "/usr/local"
    p File.expand_path("bin")            #=> "/usr/local/bin"
    p File.expand_path("../bin")         #=> "/usr/bin"
    p File.expand_path("bin", "/usr")    #=> "/usr/bin"
    p File.expand_path("../etc", "/usr") #=> "/etc"

    在 Unix 中,可以用 ~ 用户名的形式获取用户的主目录(home directory)。~/ 表示当前用户的主目录。

    p File.expand_path("~gotoyuzo/bin")    #=> "/home/gotoyuzo/bin"
    p File.expand_path("~takahashim/bin")  #=> "/home/takahashim/bin"
    p File.expand_path("~/bin")            #=> "/home/gotoyuzo/bin"

与操作文件相关的库

接下来我们来介绍一下 Ruby 默认提供的与操作文件相关的库。预定义的 File 类与 Dir 类只提供了 OS 中 Ruby 可以操作的最基本的功能。为了提高写程序的效率,有必要掌握本节中所介绍的库。

find 库

find 库中的 find 模块被用于对指定的目录下的目录或文件做递归处理。

  • Find.find(dir){|path| …}

  • Find.prune

    Find.find 方法会将目录 dir 下的所有文件路径逐个传给路径 path。

    使用 Find.find 方法时,调用 Find.prune 方法后,程序会跳过当前查找目录下的所有路径(只是使用 next 时,则只会跳过当前目录,子目录的内容还是会继续查找)。

    下面是一个显示命令行参数指定目录下内容的脚本。listdir 方法会显示参数 top 路径下所有的目录名。将不需要查找的目录设定到 IGNORES 后,就可以通过 Find.prune 方法忽略那些目录下的内容的处理。

    require 'find'
     
    IGNORES = [ /^\./, /^CVS$/, /^RCS$/ ]
     
    def listdir(top)
    Find.find(top) do |path|
        if FileTest.directory?(path)  # 如果path 是目录
        dir, base = File.split(path)
        IGNORES.each do |re|
            if re =~ base             # 需要忽略的目录
            Find.prune              # 忽略该目录下的内容的查找
            end
        end
        puts path                   # 输出结果
        end
    end
    end
     
    listdir(ARGV[0])

tempfile 库

tempfile 库用于管理临时文件。

在处理大量数据的程序中,有时候会将一部分正在处理的数据写入到临时文件。这些文件一般在程序执行完毕后就不再需要,因此必须删除,但为了能够确实删除文件,就必须记住每个临时文件的名称。此外,有时候程序还会同时处理多个文件,或者同时执行多个程序,考虑到这些情况,临时文件还不能使用相同的名称,而这就形成了一个非常麻烦的问题。

tempfile 库中的 Tempfile 类就是为了解决上述问题而诞生的。

  • Tempfile.new(basename[, tempdir])

    创建临时文件。实际生成的文件名的格式为“basename+ 进程 ID+ 流水号”。因此,即使使用同样的 basename,每次调用 new 方法生成的临时文件也都是不一样的。如果不指定目录名 tempdir,则会按照顺序查找 ENV["TMPDIR"]、ENV["TMP"]、ENV["TEMP"]、/tmp,并把最先找到的目录作为临时目录使用。

  • tempfile.close(real)

    关闭临时文件。real 为 ture 时则马上删除临时文件。即使没有明确指定删除,Tempfile 对象也会在 GC 的时候并一并删除。real 的默认值为 false。

  • tempfile.open

    再次打开 close 方法关闭的临时文件。

  • tempfile.path

    返回临时文件的路径。

fileutils 库

在之前的内容中,我们已经接触过了 fileutils 库的 FileUtils.cp、FileUtils.mv 方法。通过 require 引用 fileutils 库后,程序就可以使用 FileUtils 模块中提供的各种方便的方法来操作文件。

  • FileUtils.cp(from, to)

    把文件从 from 拷贝到 to。to 为目录时,则在 to 下面生成与 from 同名的文件。此外,也可以将 from 作为数组来一次性拷贝多个文件,这时 to 必须指定为目录。

    FileUtils.cp_r(from, to)

    功能与 FileUtils.cp 几乎一模一样,不同点在于 from 为目录时,则会进行递归拷贝。

  • FileUtils.mv(from, to)

    把文件(或者目录)from 移动到 to。to 为目录时,则将文件作为与 from 同名的文件移动到 to 目录下。也可以将 from 作为数组来一次性移动多个文件,这时 to 必须指定为目录。

  • FileUtils.rm(path)

  • FileUtils.rm_f(path)

    删除 path。path 只能为文件。也可以将 path 作为数组来一次性删除多个文件。FileUtils.rm 方法在执行删除处理的过程中,若发生异常则中断处理,而 FileUtils.rm_f 方法则会忽略错误,继续执行。

  • FileUtils.rm_r(path)

  • FileUtils.rm_rf(path)

    删除 path。path 为目录时,则进行递归删除。此外,也可以将 path 作为数组来一次性删除多个文件(或者目录)。FileUtils.rm_r 方法在执行处理的过程中,若发生异常则中断处理,而 FileUtils.rm_rf 方法则会忽略错误,继续执行。

  • FileUtils.compare(from, to)

    比较 from 与 to 的内容,相同则返回 true,否则则返回 false。

  • FileUtils.install(from, to[, option])

    把文件从 from 拷贝到 to。如果 to 已经存在,且与 from 内容一致,则不会拷贝。option 参数用于指定目标文件的访问权限,如下所示。

    FileUtils.install(from, to, :mode => 0755)
  • FileUtils.mkdir_p(path)

    使用 Dir.mkdir 方法创建 "foo/bar/baz" 这样的目录时,需要像下面那样按顺序逐个创建上层目录。

    Dir.mkdir("foo")
    Dir.mkdir("foo/bar")
    Dir.mkdir("foo/bar/baz")

    而如果使用 FileUtils.mkdir\_p 方法,则只需调用一次就可以自动创建各层的目录。此外,也可以将 path 作为数组来一次性创建多个目录。

    FileUtils.mkdir_p("foo/bar/baz")

关于 GC

我们介绍了各种类型的对象,而在程序中生成这些对象(一部分除外)时都会消耗内存空间。例如数组、字符串等,如果长度变大了,那么它们需要的内存空间也会随之变大。程序为了能正常运行不可避免地要创建对象,但是计算机的内存空间却不是可以无限使用的,因此就必须释放已经不需要的对象所占用的内存空间。

下面的情况下,变量 line 引用的字符串,在下一次读取时就不能再被引用了。

io.each_line do |line|
  print(line)
end

还有,在方法执行完毕后,在方法中临时生成的对象也不再需要了。

def hello(name)
  msg = "Hello, #{name}"    #=> 创建新的字符串对象
  puts(msg)
end

但是,内存空间释放并不是大部分程序主要关心的功能,而且忘记释放内存,或者错把正在用的对象释放等,都很可能引起难缠的程序漏洞(bug)。因此,在 Ruby(Java、Perl、Lisp 等语言也都具备这样的功能)中,解析器(interpreter)会在适当的时机,释放已经没有被任何地方引用的对象所占的资源。这样的功能,我们称之为 Garbage Collection(垃圾回收的意思),简称 GC。

有了 GC 后,我们就无需再为内存管理而烦恼了。GC 是支撑 Ruby 的宗旨——快乐编程的重要功能之一。

PreviousEncoding类NextIO