therubyway:ruby way的Io的 2

  1 检测文件是否存在及其大小

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

flag = FileTest::exist?("LochNessMonster") 
flag = FileTest::exists?("UFO") 
# exists? is a synonym for exist?


  如果我们想要知道文件是否有内容可以使用File::Statzero? 思路方法:

flag = File.("somefile").stat.zero?

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

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

 File.("myfile").stat.size? 
 puts "The file has contents." 
 
 puts "The file is empty." 
end


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

flag1 = FileTest::zero?("file1") 
flag2 = FileTest::size?("file2")


  这里还有个size思路方法:

size1 = File.size("file1") 
size2 = File.stat("file2").size 


  2 检测特殊文件属性

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

  unix/linux有面向和面向块设备FileTest思路方法blockdev?和chardev?可以进行测试:

flag1 = FileTest::chardev?("/dev/hdisk0") # false 
flag2 = FileTest::blockdev?("/dev/hdisk0") # true


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

flag1 = STDIN.tty?          # true 
flag2 = File.("diskfile").isatty # false


  个流可以是个管道或者:

flag1 = FileTest::pipe?(myfile) 
flag2 = FileTest::?(myfile)


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

file1 = File.("/tmp") 
file2 = File.("/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、fo、link或).

this_kind = File.ftype("/dev/hdisk0")   # "blockSpecial" 
that_kind = File.("/tmp").stat.ftype  # "directory"


  要测试个文件是否为另个文件链接可以使用FileTestsymlink?思路方法要计算链接数量可以使用nlink思路方法:

File.symlink("yourfile","myfile")      # Make a link 
is_sym = FileTest::symlink?("myfile")    # true 
hard_count = File.("myfile").stat.nlink # 0


  3 使用管道

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

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形式:

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对象:

IO.popen("-") do |mypipe| 
  mypipe 
  puts "I'm the parent: pid = #{Process.pid}" 
  listen = mypipe.gets 
  puts listen 
  
  puts "I'm the child: pid = #{Process.pid}" 
 end 
end 
 
# Prs: 
#  I'm the parent: pid = 10580 
#  I'm the child: pid = 10582


  pipe思路方法也返回互相连接对管道:

pipe = IO.pipe 
reader = pipe[0] 
writer = pipe[1] 
 
str = nil 
thread1 = Thread.(reader,writer) do |reader,writer| 
 # writer.close_write 
 str = reader.gets 
 reader.close 
end 
 
thread2 = Thread.(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你可以这样做:

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  to true 
 
mysock.nonblock(false) { other_operation(mysock) } 
# Perform other_operation with non-blocking  to false


  5 使用readpartial

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

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

data = sock.readpartial(128) # Read at most 128 s

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

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

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

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

  当sysread 在阻塞模式下行为和readpartial相似.

  6 操作路径名

  先来看下File.dirname和File.basename思路方法:

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思路方法可以将个文件路径名和文件名分隔开:

info = File.split(str)    # ["/home/dave","podbay.rb"]

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

Dir.chdir("/home/poole/personal/docs") 
abs = File.expand_path("../../misc")  # "/home/poole/misc"


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

file = File.("../../foobar") 
 
name = file.path         # "../../foobar"


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

path = File.join("usr","local","bin","someprog")

  7使用Pathname

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

require 'pathname' 
path = Pathname.("home/hal") 
file = Pathname.("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


  再看看其他有用思路方法:

p1 = Pathname.("//")      # odd but legal 
p1.root?             # true 
p2 = Pathname.("/home/poole") 
p3 = p2.parent          # Pathname:/home 
items = p2.children        # .gif' /> of Pathnames (all files and 
                 # dirs immediately under poole)


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

p1 = Pathname.("/home/dave") 
p1.absolute?           # true 
p1.relative?           # false


  8  Command-Level 文件操作

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

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 s


  fileUtils也有很多有用思路方法

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  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.("foo.so","/usr/lib")


  9 从键盘抓取输入

  也就是抓取用户从键盘输入

  unix平台:

def getchar 
 system("stty raw -echo") # Raw mode, no echo 
 char = STDIN.getc 
 system("stty -raw echo") # Re terminal mode 
 char 
end


  windows平台:

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


  10 读取整个文件到内存

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

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(它返回个大串):

str = IO.read("myfile") 
s = arr.size 
puts "myfile has #{s} s in it." 
 
longest = str.collect {|x| x.length}.max   # s are enumerable! 
puts "The longest line in it has #{longest} characters." 


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

  11 逐行迭代个文件

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

# Pr all lines containing the word "target" 
IO.foreach("somefile") do |line| 
 puts line  line =~ /target/ 
end 
 
# Another way... 
file = File.("somefile") 
file.each do |line| 
 puts line  line =~ /target/ 
end


  12逐字节对文件进行遍历

  可以使用each_思路方法如果你想要转换话使用chr思路方法:

file = File.("myfile") 
e_count = 0 
file.each_ do || 
 e_count  1    ?e 
end


  12 把串当文件来用

  我们可以使用io库:

require 'io' 
 
ios = StringIO.("abcdefghijkl\nABC\n123") 
 
ios.seek(5) 
ios.puts("xyz") 
 
puts ios.tell       # 8 
 
puts ios..dump   # "abcdexyzijkl\nABC\n123" 
 
c = ios.getc 
puts "c = #{c}"      # c = 105 
 
ios.ungetc(?w) 
 
puts ios..dump   # "abcdexyzwjkl\nABC\n123" 
 
puts "Ptr = #{ios.tell}" 
 
s1 = ios.gets       # "wjkl" 
s2 = ios.gets       # "ABC"


  13读取嵌套在数据

  ruby中末尾__END__ 标记介绍说明下面数据是内嵌数据你可以使用个IO对象DATA来读取

# Pr 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,它将会将文件指针指向开头:

DATA.rewind 
num = 1 
DATA.each_line do |line| 
 puts "#{'%03d' % num} #{line}" 
 num  1 
end 
__END__


  15 操作临时文件

  这里使用Tempfile库:

require "tempfile" 
 
temp = Tempfile.("stuff") 
name = temp.path       # "/tmp/stuff17060.0" 
temp.puts "Kilroy was here" 
temp.close 
 
# Later... 
temp.open 
str = temp.gets        # "Kilroy was here" 
temp.close(true)       # 立即删除


  16 改变和设置当前目录

  得到当前目录可以使用Dir.pwd或他别名Dir.getwd来获得.

  Dir.chdir 用来改变当前目录:

Dir.chdir("/var/tmp") 
 
puts Dir.pwd          # "/var/tmp" 
 
puts Dir.getwd        # "/var/tmp"


  这个还能接受个block,接受block介绍说明block里代码都是在改变了目录下进行:

Dir.chdir("/home") 
Dir.chdir("/tmp") do 
 puts Dir.pwd    # /tmp 
 # other code... 
end 
puts Dir.pwd     # /home


  17改变当前根目录

Dir.chdir("/home/guy/sandbox/tmp") 
 
Dir.chroot("/home/guy/sandbox") 
 
puts Dir.pwd          # "/tmp"


  18 遍历个目录

Dir.foreach("/tmp") { |entry| puts entry } 
 
dir = Dir.("/tmp") 
dir.each { |entry| puts entry }


  19 创建个目录链

  在linux使用mkdir -p来做在ruby中我么可以这么做:

require "fileutils" 
 
FileUtils.makedirs("/tmp/these/dirs/need/not/exist")


  20 递归删除目录

  在linux下我们能够使用rm -rf ...来做,在ruby中我们能这么做:

require 'pathname' 
 
dir = Pathname.("/home/poole/") 
 
dir.rmtree 
 
# or: 
 
require 'fileutils' 
 
FileUtils.rm_r("/home/poole")


  21 查找文件和目录

  使用find库来做:

require "find" 
 
def findfiles(dir, name) 
 list =  
 Find.find(dir) do |path| 
  Find.prune  [".",".."].? path 
   name 
   when String 
    list << path  File.basename(path)  name 
   when Regexp 
    list << path  File.basename(path) =~ name 
   
   raise ArgumentError 
  end 
 end 
 list 
end 
 
findfiles "/home/hal", "toc.txt" 
# ["/home/hal/docs/toc.txt", "/home/hal/misc/toc.txt"] 
 
findfiles "/home", /^[a-z]+.doc/ 
# ["/home/hal/docs/alpha.doc", "/home/guy/guide.doc", 
# "/home/bill/help/readme.doc"]


Tags:  ruby安装 ruby是什么意思 rubyonrails therubyway

延伸阅读

最新评论

发表评论