`

ruby文件操作

阅读更多
 转!
1 检测文件是否存在及其大小

FileTest的 exist?方法可以检测一个文件是否存在:

Ruby代码 复制代码
  1. flag = FileTest::exist?("LochNessMonster")   
  2. flag = FileTest::exists?("UFO")   
  3. # exists? is a synonym for exist?  
flag = FileTest::exist?("LochNessMonster")
flag = FileTest::exists?("UFO")
# exists? is a synonym for exist?


如果我们想要知道文件是否有内容,可以使用File::Stat的zero? 方法:

Ruby代码 复制代码
  1. flag = File.new("somefile").stat.zero?  
flag = File.new("somefile").stat.zero?


这个将会返回true,这是因为在ruby中0也是true,nil才是false.

所以我们可以使用size?方法:

Ruby代码 复制代码
  1. if File.new("myfile").stat.size?   
  2.   puts "The file has contents."  
  3. else  
  4.   puts "The file is empty."  
  5. end  
if File.new("myfile").stat.size?
  puts "The file has contents."
else
  puts "The file is empty."
end


FileTest模块里面也有zero? 和size?方法:

Ruby代码 复制代码
  1. flag1 = FileTest::zero?("file1")   
  2. flag2 = FileTest::size?("file2")  
flag1 = FileTest::zero?("file1")
flag2 = FileTest::size?("file2")


这里还有一个size方法:

Ruby代码 复制代码
  1. size1 = File.size("file1")   
  2. size2 = File.stat("file2").size  
size1 = File.size("file1")
size2 = File.stat("file2").size


2 检测特殊文件属性

这边要注意,File类mix了FIleTest模块,并且FileTest模块和File::Stat模块功能上也有很多重复.

unix/linux有面向字符和面向块的设备。FileTest的方法blockdev?和chardev?可以进行测试:

Ruby代码 复制代码
  1. flag1 = FileTest::chardev?("/dev/hdisk0")  # false   
  2. flag2 = FileTest::blockdev?("/dev/hdisk0"# true  
flag1 = FileTest::chardev?("/dev/hdisk0")  # false
flag2 = FileTest::blockdev?("/dev/hdisk0") # true


有时我们想要知道一个流是否联系到了终端,这时我们可以使用IO类的tty?方法:

Ruby代码 复制代码
  1. flag1 = STDIN.tty?                   # true   
  2. flag2 = File.new("diskfile").isatty  # false  
flag1 = STDIN.tty?                   # true
flag2 = File.new("diskfile").isatty  # false


一个流可以是一个管道,或者一个socket:

Ruby代码 复制代码
  1. flag1 = FileTest::pipe?(myfile)   
  2. flag2 = FileTest::socket?(myfile)  
flag1 = FileTest::pipe?(myfile)
flag2 = FileTest::socket?(myfile)


要区分目录和普通文件我们这样使用:

Ruby代码 复制代码
  1. file1 = File.new("/tmp")   
  2. file2 = File.new("/tmp/myfile")   
  3. test1 = file1.directory?          # true   
  4. test2 = file1.file?               # false   
  5. test3 = file2.directory?          # false   
  6. test4 = file2.file?               # true  
file1 = File.new("/tmp")
file2 = File.new("/tmp/myfile")
test1 = file1.directory?          # true
test2 = file1.file?               # false
test3 = file2.directory?          # false
test4 = file2.file?               # true


File还有一个类方法ftype,他将返回流的类型.他也在File::Stat里面,只不过是实例方法.它的返回值可能是下面的字符

串(file、directory、blockSpecial、characterSpecial、fifo、link或socket).

Ruby代码 复制代码
  1. this_kind = File.ftype("/dev/hdisk0")     # "blockSpecial"   
  2. that_kind = File.new("/tmp").stat.ftype   # "directory"  
this_kind = File.ftype("/dev/hdisk0")     # "blockSpecial"
that_kind = File.new("/tmp").stat.ftype   # "directory"


要测试一个文件是否为另一个文件的链接,可以使用FileTest的symlink?方法,要计算链接数量,可以使用nlink方法:

Ruby代码 复制代码
  1. File.symlink("yourfile","myfile")           # Make a link   
  2. is_sym = FileTest::symlink?("myfile")       # true   
  3. hard_count = File.new("myfile").stat.nlink  # 0  
File.symlink("yourfile","myfile")           # Make a link
is_sym = FileTest::symlink?("myfile")       # true
hard_count = File.new("myfile").stat.nlink  # 0


3 使用管道

ruby中使用IO.popen打开管道:

Ruby代码 复制代码
  1. check = IO.popen("spell","r+")   
  2. check.puts("'T was brillig, and the slithy toves")   
  3. check.puts("Did gyre and gimble in the wabe.")   
  4. check.close_write   
  5. list = check.readlines   
  6. list.collect! { |x| x.chomp }   
  7. # list is now %w[brillig gimble gyre slithy toves wabe]  
check = IO.popen("spell","r+")
check.puts("'T was brillig, and the slithy toves")
check.puts("Did gyre and gimble in the wabe.")
check.close_write
list = check.readlines
list.collect! { |x| x.chomp }
# list is now %w[brillig gimble gyre slithy toves wabe]


要注意 必须调用close_write,如果没有调用它,读取管道的时候,就不能到达文件的末尾.

下面是一个block的形式:

Ruby代码 复制代码
  1. File.popen("/usr/games/fortune"do |pipe|   
  2.   quote = pipe.gets   
  3.   puts quote   
  4.   # On a clean disk, you can seek forever. - Thomas Steel   
  5. end  
File.popen("/usr/games/fortune") do |pipe|
  quote = pipe.gets
  puts quote
  # On a clean disk, you can seek forever. - Thomas Steel
end



如果指定了一个字符串"-",那么一个新的ruby实例将被创建.如果指定了一个block,那么这个block将会作为两个独立

的进程运行。子进程得到nil,父进程得到一个IO对象:

Ruby代码 复制代码
  1. IO.popen("-"do |mypipe|   
  2.   if mypipe   
  3.     puts "I'm the parent: pid = #{Process.pid}"  
  4.     listen = mypipe.gets   
  5.     puts listen   
  6.   else  
  7.     puts "I'm the child: pid = #{Process.pid}"  
  8.   end  
  9. end  
  10.   
  11. # Prints:   
  12. #   I'm the parent: pid = 10580   
  13. #   I'm the child: pid = 10582  
IO.popen("-") do |mypipe|
  if mypipe
    puts "I'm the parent: pid = #{Process.pid}"
    listen = mypipe.gets
    puts listen
  else
    puts "I'm the child: pid = #{Process.pid}"
  end
end

# Prints:
#   I'm the parent: pid = 10580
#   I'm the child: pid = 10582


pipe方法也返回互相连接的一对管道:

Ruby代码 复制代码
  1. pipe = IO.pipe   
  2. reader = pipe[0]   
  3. writer = pipe[1]   
  4.   
  5. str = nil  
  6. thread1 = Thread.new(reader,writer) do |reader,writer|   
  7.   # writer.close_write   
  8.   str = reader.gets   
  9.   reader.close   
  10. end  
  11.   
  12. thread2 = Thread.new(reader,writer) do |reader,writer|   
  13.   # reader.close_read   
  14.   writer.puts("What hath God wrought?")   
  15.   writer.close   
  16. end  
  17.   
  18. thread1.join   
  19. thread2.join   
  20.   
  21. puts str         # What hath God wrought?  
pipe = IO.pipe
reader = pipe[0]
writer = pipe[1]

str = nil
thread1 = Thread.new(reader,writer) do |reader,writer|
  # writer.close_write
  str = reader.gets
  reader.close
end

thread2 = Thread.new(reader,writer) do |reader,writer|
  # reader.close_read
  writer.puts("What hath God wrought?")
  writer.close
end

thread1.join
thread2.join

puts str         # What hath God wrought?


4 使用非阻塞IO

ruby会在后台执行一些操作,使io不会被阻断,因此大部分情况下可以使用ruby线程来管理IO,当一个线程被Io阻塞之

后,另外的线程能够继续执行.

由于ruby的线程不是一个native的线程,因此ruby的线程都在同一个进程里面.

如果你想关闭一个非阻塞io,你可以这样做:

Ruby代码 复制代码
  1. require 'io/nonblock'  
  2.   
  3. # ...   
  4.   
  5. test = mysock.nonblock?         # false   
  6.   
  7. mysock.nonblock = true          # turn off blocking   
  8. # ...   
  9. mysock.nonblock = false         # turn on again   
  10.   
  11. mysock.nonblock { some_operation(mysock) }   
  12. # Perform some_operation with nonblocking set to true   
  13.   
  14. mysock.nonblock(false) { other_operation(mysock) }   
  15. # Perform other_operation with non-blocking set to false  
require 'io/nonblock'

# ...

test = mysock.nonblock?         # false

mysock.nonblock = true          # turn off blocking
# ...
mysock.nonblock = false         # turn on again

mysock.nonblock { some_operation(mysock) }
# Perform some_operation with nonblocking set to true

mysock.nonblock(false) { other_operation(mysock) }
# Perform other_operation with non-blocking set to false


5 使用readpartial

readpartial被设计来用于就像socket这样的流.

readpartial要求提供最大长度的参数,如果指定了buffer,那么这个buffer应指向用于存储数据的一个字符串。

Ruby代码 复制代码
  1. data = sock.readpartial(128)  # Read at most 128 bytes  
data = sock.readpartial(128)  # Read at most 128 bytes


readpartial 方法,不能接受非阻塞的flag,他有时会阻塞:IO对象的buffer是空的;流的内容为空;流没有到达文件末尾



因此,如果流中还有数据的话,readpartial将不会阻塞.

如果流没有数据,并且他已经抵达文件的末尾,readpartial 将会立即抛出一个EOFError.

如果调用阻塞,他将会等待直到接收到数据或者得到一个EOF.

当sysread 调用在阻塞模式下,他的行为与readpartial相似.

6 操作路径名


先来看一下File.dirname和File.basename方法:
Ruby代码 复制代码
  1. str = "/home/dave/podbay.rb"  
  2. dir = File.dirname(str)           # "/home/dave"   
  3. file1 = File.basename(str)        # "podbay.rb"   
  4. file2 = File.basename(str,".rb")  # "podbay"  
str = "/home/dave/podbay.rb"
dir = File.dirname(str)           # "/home/dave"
file1 = File.basename(str)        # "podbay.rb"
file2 = File.basename(str,".rb")  # "podbay"


File.split方法,可以将一个文件的路径名和文件名分隔开:

Ruby代码 复制代码
  1. info = File.split(str)        # ["/home/dave","podbay.rb"]  
info = File.split(str)        # ["/home/dave","podbay.rb"]


类方法expand_path 将一个相对路径,转换为一个绝对路径名:

Ruby代码 复制代码
  1. Dir.chdir("/home/poole/personal/docs")   
  2. abs = File.expand_path("../../misc")    # "/home/poole/misc"  
Dir.chdir("/home/poole/personal/docs")
abs = File.expand_path("../../misc")    # "/home/poole/misc"


对于打开的文件,path 将会返回这个文件的路径名:

Ruby代码 复制代码
  1. file = File.new("../../foobar")   
  2.   
  3. name = file.path                 # "../../foobar"  
file = File.new("../../foobar")

name = file.path                 # "../../foobar"


类方法类方法join正好和split相反:

Ruby代码 复制代码
  1. path = File.join("usr","local","bin","someprog")  
path = File.join("usr","local","bin","someprog")


7使用Pathname

pathname类实际上是,Dir, File, FileTest,和FileUtils的包装器,它包含他们的很多功能:

Ruby代码 复制代码
  1. require 'pathname'  
  2. path = Pathname.new("home/hal")   
  3. file = Pathname.new("file.txt")   
  4. p2 = path + file   
  5. path.directory?         # true   
  6. path.file?              # false   
  7. p2.directory?           # false   
  8. p2.file?                # true   
  9.   
  10. puts parts = p2.split     # [Pathname:/home/hal, Pathname:file.txt]   
  11. puts ext = p2.extname     # .txt  
require 'pathname'
path = Pathname.new("home/hal")
file = Pathname.new("file.txt")
p2 = path + file
path.directory?         # true
path.file?              # false
p2.directory?           # false
p2.file?                # true

puts parts = p2.split     # [Pathname:/home/hal, Pathname:file.txt]
puts ext = p2.extname     # .txt


再看看其他的有用的方法:

Ruby代码 复制代码
  1. p1 = Pathname.new("//")           # odd but legal   
  2. p1.root?                          # true   
  3. p2 = Pathname.new("/home/poole")   
  4. p3 = p2.parent                    # Pathname:/home   
  5. items = p2.children               # array of Pathnames (all files and   
  6.                                   # dirs immediately under poole)  
p1 = Pathname.new("//")           # odd but legal
p1.root?                          # true
p2 = Pathname.new("/home/poole")
p3 = p2.parent                    # Pathname:/home
items = p2.children               # array of Pathnames (all files and
                                  # dirs immediately under poole)


relative和absolute判断路径是否是相对的:

Ruby代码 复制代码
  1. p1 = Pathname.new("/home/dave")   
  2. p1.absolute?                      # true   
  3. p1.relative?                      # false  
p1 = Pathname.new("/home/dave")
p1.absolute?                      # true
p1.relative?                      # false


8 Command-Level 文件操作

其实也就是copy, delete, rename,等等 些操作了:

Ruby代码 复制代码
  1. File.delete("history")   
  2. File.unlink("toast")   
  3. File.rename("Ceylon","SriLanka")   
  4. File.link("/etc/hosts","/etc/hostfile")   # hard link   
  5. File.symlink("/etc/hosts","/tmp/hosts")   # symbolic link   
  6. File.truncate("myfile",1000)    # Now at most 1000 bytes  
File.delete("history")
File.unlink("toast")
File.rename("Ceylon","SriLanka")
File.link("/etc/hosts","/etc/hostfile")   # hard link
File.symlink("/etc/hosts","/tmp/hosts")   # symbolic link
File.truncate("myfile",1000)    # Now at most 1000 bytes


fileUtils也有很多有用的方法
Ruby代码 复制代码
  1. require "fileutils"  
  2. same = FileUtils.compare_file("alpha","beta")  # true   
  3. # Copy epsilon to theta and log any errors.   
  4. FileUtils.copy("epsilon","theta"true)   
  5. FileUtils.move("/tmp/names","/etc")     # Move to new directory   
  6. FileUtils.move("colours","colors")      # Just a rename   
  7. FileUtils.safe_unlink("alpha","beta","gamma")   
  8. # Log errors on the next two files   
  9. FileUtils.safe_unlink("delta","epsilon",true)   
  10. FileUtils.install("foo.so","/usr/lib")  
require "fileutils"
same = FileUtils.compare_file("alpha","beta")  # true
# Copy epsilon to theta and log any errors.
FileUtils.copy("epsilon","theta", true)
FileUtils.move("/tmp/names","/etc")     # Move to new directory
FileUtils.move("colours","colors")      # Just a rename
FileUtils.safe_unlink("alpha","beta","gamma")
# Log errors on the next two files
FileUtils.safe_unlink("delta","epsilon",true)
FileUtils.install("foo.so","/usr/lib")


9 从键盘抓取输入

也就是抓取用户从键盘输入的字符。
unix平台:

Ruby代码 复制代码
  1. def getchar   
  2.   system("stty raw -echo")  # Raw mode, no echo   
  3.   char = STDIN.getc   
  4.   system("stty -raw echo")  # Reset terminal mode   
  5.   char   
  6. end  
def getchar
  system("stty raw -echo")  # Raw mode, no echo
  char = STDIN.getc
  system("stty -raw echo")  # Reset terminal mode
  char
end


windows平台:

Ruby代码 复制代码
  1. require 'Win32API'  
  2.   
  3. def getchar   
  4.   char = Win32API.new("crtdll""_getch", [], 'L').Call   
  5. end  
require 'Win32API'

def getchar
  char = Win32API.new("crtdll", "_getch", [], 'L').Call
end


10 读取整个文件到内存

读取整个文件到数组,你不需要打开文件,IO.readlines 可以完成这个工作,他自己会open和close.

Ruby代码 复制代码
  1. arr = IO.readlines("myfile")   
  2. lines = arr.size   
  3. puts "myfile has #{lines} lines in it."  
  4.   
  5. longest = arr.collect {|x| x.length}.max   
  6. puts "The longest line in it has #{longest} characters."  
arr = IO.readlines("myfile")
lines = arr.size
puts "myfile has #{lines} lines in it."

longest = arr.collect {|x| x.length}.max
puts "The longest line in it has #{longest} characters."


也可以用IO.read(它返回一个大的字符串):

Ruby代码 复制代码
  1. str = IO.read("myfile")   
  2. bytes = arr.size   
  3. puts "myfile has #{bytes} bytes in it."  
  4.   
  5. longest = str.collect {|x| x.length}.max     # strings are enumerable!   
  6. puts "The longest line in it has #{longest} characters."  
str = IO.read("myfile")
bytes = arr.size
puts "myfile has #{bytes} bytes in it."

longest = str.collect {|x| x.length}.max     # strings are enumerable!
puts "The longest line in it has #{longest} characters."


由于File继承了IO,因此File也有这两个方法.

11 逐行迭代一个文件

我们可以使用IO.foreach 方法,或者each方法,如果是前者文件不需要显示打开:

Ruby代码 复制代码
  1. # Print all lines containing the word "target"   
  2. IO.foreach("somefile"do |line|   
  3.   puts line if line =~ /target/   
  4. end  
  5.   
  6. # Another way...   
  7. file = File.new("somefile")   
  8. file.each do |line|   
  9.   puts line if line =~ /target/   
  10. end  
# Print all lines containing the word "target"
IO.foreach("somefile") do |line|
  puts line if line =~ /target/
end

# Another way...
file = File.new("somefile")
file.each do |line|
  puts line if line =~ /target/
end


12逐字节对文件进行遍历

可以使用each_byte方法,如果你想要转换byte到字符的话使用chr方法:

Ruby代码 复制代码
  1. file = File.new("myfile")   
  2. e_count = 0   
  3. file.each_byte do |byte|   
  4.   e_count += 1 if byte == ?e   
  5. end  
file = File.new("myfile")
e_count = 0
file.each_byte do |byte|
  e_count += 1 if byte == ?e
end


12 把字符串当文件来用

我们可以使用stringio库:

Ruby代码 复制代码
  1. require 'stringio'  
  2.   
  3. ios = StringIO.new("abcdefghijkl\nABC\n123")   
  4.   
  5. ios.seek(5)   
  6. ios.puts("xyz")   
  7.   
  8. puts ios.tell             # 8   
  9.   
  10. puts ios.string.dump      # "abcdexyzijkl\nABC\n123"   
  11.   
  12. c = ios.getc   
  13. puts "c = #{c}"           # c = 105   
  14.   
  15. ios.ungetc(?w)   
  16.   
  17. puts ios.string.dump      # "abcdexyzwjkl\nABC\n123"   
  18.   
  19. puts "Ptr = #{ios.tell}"  
  20.   
  21. s1 = ios.gets             # "wjkl"   
  22. s2 = ios.gets             # "ABC"  
require 'stringio'

ios = StringIO.new("abcdefghijkl\nABC\n123")

ios.seek(5)
ios.puts("xyz")

puts ios.tell             # 8

puts ios.string.dump      # "abcdexyzijkl\nABC\n123"

c = ios.getc
puts "c = #{c}"           # c = 105

ios.ungetc(?w)

puts ios.string.dump      # "abcdexyzwjkl\nABC\n123"

puts "Ptr = #{ios.tell}"

s1 = ios.gets             # "wjkl"
s2 = ios.gets             # "ABC"


13读取嵌套在程序中的数据

ruby中程序末尾的__END__ 标记说明,下面的数据是程序内嵌的数据,你可以使用一个IO对象DATA来读取。

Ruby代码 复制代码
  1. # Print each line backwards...   
  2. DATA.each_line do |line|   
  3.   puts line.reverse   
  4. end  
  5. __END__   
  6. A man, a plan, a canal... Panama!   
  7. Madam, I'm Adam.   
  8. ,siht daer nac uoy fI   
  9. .drah oot gnikrow neeb ev'uoy  
# Print each line backwards...
DATA.each_line do |line|
  puts line.reverse
end
__END__
A man, a plan, a canal... Panama!
Madam, I'm Adam.
,siht daer nac uoy fI
.drah oot gnikrow neeb ev'uoy


14 读取程序源码

DATA指向__END__ 后面的数据,如果你调用rewind,它将会将文件指针指向程序的开头:

Ruby代码 复制代码
  1. DATA.rewind   </spa>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics