Ruby 简明教程 Part 8

1.简介

2.安装

3.基本语法

4高级进阶

 

------继续

3.基本语法

3.16   File I/O  文件 输入/输出

 Ruby 在kernel模块实现了I/O相关的方法。这些I/O 方法都是 IO 类派生的。html

IO 类提供了 基本方法: read, write, gets, puts, readline, getc, and printf.数组

本节介绍这些基本方法。ruby

3.16.1 The puts Statement

 puts  显示变量的内容,在末尾添加新行。socket

#!/usr/bin/ruby

val1 = "This is variable one"
val2 = "This is variable two"
puts val1
puts val2

结果: 函数

This is variable one
This is variable two

3.16.2 The gets Statement

  gets  从标准屏幕STDIN 获取任何用户输入。ui

 下例,显示提示输入信息,而后将用户输入接受,保存到变量,而后打印变量到STDOUT。this



#!/usr/bin/ruby操作系统

puts "Enter a value :"指针

val = getscode

puts val

结果:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_gets.rb
Enter a value :
this is what I entered 
this is what I entered 

3.16.3 The putc Statement

 putc 能够输出一次一个字符。

 

#!/usr/bin/ruby

str = "Hello Ruby!"
putc str

结果:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_putc.rb
H

3.16.4 The print Statement

print  与 puts 相似。惟一不一样的是,puts 换行,而print  光标停在同行。

 

print "Hello World"
print "Good Morning"

结果:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_print.rb
Hello WorldGood Morning

3.16.5 Opening and Closing Files 打开和关闭文件

 

The File.new Method

用 File.new 方法建立文件对象,来读,写或读写文件,取决于mode 方式。 用File.close 关闭文件。

格式

aFile = File.new("filename", "mode")
   # ... process the file
aFile.close

The File.open Method

File.open 方式建立新的文件对象,将文件对象赋值给一个文件。 File.open method 能够关联block,而File.new不行。

File.open("filename", "mode") do |aFile|
   # ... process the file
end

 

Reading and Writing Files 对写文件

简单的I/O方法,一样适用于文件对象。

不过, I/O对象有更多访问方式。 

The sysread Method   

能够用sysread 读文件的内容。使用sysread读时, 能够用任何mode打开的文件。

 input.txt

This is a simple text file for testing purpose. 

例子:demo_sysread.rb

aFile = File.new("input.txt", "r")
if aFile
   content = aFile.sysread(20)
   puts content
else
   puts "Unable to open file!"
end

将输出前20个字符,文件指针将停留在第21个字符的位置。

The syswrite Method

用 syswrite 将内容写入文件。使用 syswrite时,须要以写方式打开文件。 

demo_syswrite.rb 

aFile = File.new("input.txt", "r+")
if aFile
   aFile.syswrite("ABCDEF")
else
   puts "Unable to open file!"
end

将 "ABCDEF" 写入文件。

The each_byte Method

each_byte  是文件类的方法。它老是与block关联。

aFile = File.new("input.txt", "r+")
if aFile
   aFile.syswrite("ABCDEF")
   aFile.each_byte {|ch| putc ch; putc ?. }
else
   puts "Unable to open file!"
end

每一个字节传给block 依次执行:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_eachbyte.rb
s. .a. .s.i.m.p.l.e. .t.e.x.t. .f.i.l.e. .f.o.r. .t.e.s.t.i.n.g. .p.u.r.p.o.s.e...

The IO.readlines Method

文件类是IO类的子类。IO的一些方法,也能够用来操做文件。

 IO.readlines. 逐行读文件内容。 demo_readlines.rb

arr = IO.readlines("input.txt")
puts arr[0]
puts arr[1]

 

The IO.foreach Method

IO.foreach 方法也是逐行输出。它与readlines 的不一样,foreach 与block 关联。不过foreach 不返回数组。

IO.foreach("input.txt"){|block| puts block}

将文件逐行传给block,执行block里的代码。

Renaming and Deleting Files

能够用rename 来重命名文件,delete 来删除文件。

重命名

# Rename a file from test1.txt to test2.txt
File.rename( "test1.txt", "test2.txt" )

删除

#!/usr/bin/ruby

# Delete file test2.txt
File.delete("test2.txt")

File Modes and Ownership 文件模式及拥有者

使用chmod 及参数 mask 改变文件的模式或权限。

 

file = File.new( "test.txt", "w" )
file.chmod( 0755 )

 这个功能和操做系统命令相似。

File Inquiries 文件查询

检查文件存在,而后打开,不存在,返回nil。

#!/usr/bin/ruby

File.open("file.rb") if File::exists?( "file.rb" )

检查参数是否为文件。

#!/usr/bin/ruby

# This returns either true or false
File.file?( "text.txt" ) 

检查文件名是不是目录。 

# a directory
File::directory?( "/usr/local/bin" ) # => true

# a file
File::directory?( "file.rb" ) # => false

如下命令检查文件是否可读,可写,或可执行。

#!/usr/bin/ruby

File.readable?( "test.txt" )   # => true
File.writable?( "test.txt" )   # => true
File.executable?( "test.txt" ) # => false

检查文件大小是否为0

#!/usr/bin/ruby

File.zero?( "test.txt" )      # => true

返回文件大小 

#!/usr/bin/ruby

File.size?( "text.txt" )     # => 1002

返回文件类型:

#!/usr/bin/ruby

File::ftype( "test.txt" )     # => file

文件类型: file, directory, characterSpecial, blockSpecial, fifo, link, socket, or unknown.

一下命令返回文件建立时间,修改时间 或最后访问时间。

#!/usr/bin/ruby

File::ctime( "test.txt" ) # => Fri May 09 10:06:37 -0700 2008
File::mtime( "text.txt" ) # => Fri May 09 10:44:44 -0700 2008
File::atime( "text.txt" ) # => Fri May 09 10:45:01 -0700 2008

Directories in Ruby

文件都包含在目录里。目录能够用Dir 类来处理。

Navigating Through Directories

 Dir.chdir 更改目录。

Dir.chdir("/usr/bin")

Dir.pwd 查看当前目录

puts Dir.pwd # This will return something like /usr/bin

Dir.entries 获取指定目录里的文件和目录列表。

puts Dir.entries("/usr/bin").join(' ')

 Dir.foreach 提供了 Dir.entries的相似功能。

Dir.foreach("/usr/bin") do |entry|
   puts entry
end

也能够用Dir类的数组方式来或目录列表。

Dir["/usr/bin/*"]

Creating a Directory

Dir.mkdir 建立目录

Dir.mkdir("mynewdir")

你也能够在建立目录时,设置权限。

NOTE − mask 755 设置 owner, group, world [anyone] 为 rwxr-xr-x  , r = read, w = write, and x = execute.

r,w,x分别表示读,写,执行。

Dir.mkdir( "mynewdir", 755 )

Deleting a Directory

Dir.delete 删除目录。Dir.unlink 和 Dir.rmdir执行一样功能。

Dir.delete("testdir")

Creating Files & Temporary Directories 建立文件和临时目录。

临时目录是程序执行过程当中建立的可是不须要永久保存的。

Dir.tmpdir 提供当前系统的临时目录路径。虽然该方式不是默承认用。不过能够使用require  导入 'tmpdir'.

能够使用 Dir.tmpdir 和 File.join建立跨平台的临时文件 

require 'tmpdir'
   tempfilename = File.join(Dir.tmpdir, "tingtong")
   tempfile = File.new(tempfilename, "w")
   tempfile.puts "This is a temporary file"
   tempfile.close
   File.delete(tempfilename)

上述代码建立临时文件,写入数据,而后删除。

Ruby的标准库有Tempfile, 能够建立临时文件 

require 'tempfile'
   f = Tempfile.new('tingtong')
   f.puts "Hello"
   puts f.path
   f.close

Built-in Functions 内置函数

更多文件和目录,参考如下文档。

 

3.17 Exception  异常

 

执行老是会出现异常。若是你打开一个文件,可是文件并不存在,就程序没有适当地处理,沉香质量就不好。

如贵异常,程序中止。所以用异常来处理各类错误,并做适当处理以防彻底中止程序。

Ruby 用 rescue 子句来处理异常。

格式

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
else  
# Other exceptions
ensure
# Always will be executed
end

若是begin 和 rescue 之间的代码抛出异常,控制传给rescue 和 end 之间的代码。

Ruby 将异常与每一个参数比较,若是匹配,则执行rescue 子句。

若是异常不匹配指定的错误类型,则能够用else 子句来处理。 

demo_rescue.rb

#!/usr/bin/ruby
begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
      file = STDIN
end
print file, "==", STDIN, "\n"

STDIN 赋值给file 由于rescue 以前代码执行异常。 .

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_rescue.rb
#<IO:0x0000559e61bcc208>==#<IO:0x0000559e61bcc208>

3.17.1 Using retry Statement

能够用rescue block 扑捉异常,用 retry 从头执行begin block 。

格式

begin
   # Exceptions raised by this code will 
   # be caught by the following rescue clause
rescue
   # This block will capture all types of exceptions
   retry  # This will move control to the beginning of begin
end

举例
#!/usr/bin/ruby
begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
   fname = "existant_file"
   retry
end

进程以下

  • 打开一个不存在的文件发生异常.
  • 到 rescue, fname 被从新赋值一个存在的文件。
  • 经过retry, 程序回到begin  开头。 
  • 此次文件成功打开文件。
  • 程序往下继续执行。

注意 − 若是从新赋值的文件也不存在,则会无限重试。 使用retry 时要当心。

3.17.2 Using raise Statement

 

使用raise 来抛出异常。

格式

raise 

OR

raise "Error Message" 

OR

raise ExceptionType, "Error Message"

OR

raise ExceptionType, "Error Message" condition

 

第一种简单讲当前异常从新抛出。这用于在传递前拦截异常的处理。

第二种建立一个新的RuntimeError,将message关联指定字符串。

第三种用第一个参数建立异常类型,将message 与第二个参数关联。

第四种和第三种相似,就是加了条件语句。

demo_raise1.rb

begin  
   puts 'I am before the raise.'  
   raise 'An error has occurred.'  
   puts 'I am after the raise.'  
rescue  
   puts 'I am rescued.'  
end  
puts 'I am after the begin block.'  

结果:

I am before the raise.  
I am rescued.  
I am after the begin block.  



demo_raise2.rb
begin  
   raise 'A test exception.'  
rescue Exception => e  
   puts e.message  
   puts e.backtrace.inspect  
end  

结果:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_raise2.rb
A test exception.
["demo_raise2.rb:2:in `<main>'"]

3.17.3 Using ensure Statement

有时候,须要在block 结束时确保某些处理执行,不管是否有异常。譬如,进入block打开文件,离开块时须要关闭文件。

ensure 子句就是来确保代码执行的。 

 

格式

begin 
   #.. process 
   #..raise exception
rescue 
   #.. handle error 
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

  demo_ensure.rb 

begin
   raise 'A test exception.'
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
ensure
   puts "Ensuring execution"
end

执行结果:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_ensure.rb
A test exception.
["demo_ensure.rb:2:in `<main>'"]
Ensuring execution

 

3.17.4 Catch and Throw

 

catch和throw 能够跳出深度嵌套的结构。

 

格式

throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end

OR

throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end

 

demo_catchthrow.rb

def promptAndGet(prompt)
   print prompt
   res = readline.chomp
   throw :quitRequested if res == "!"
   return res
end

catch :quitRequested do
   name = promptAndGet("Name: ")
   age = promptAndGet("Age: ")
   sex = promptAndGet("Sex: ")
   # ..
   # process information
end
promptAndGet("Name:")

运行此程序,手动交互。例如:

zzl@zzl-VirtualBox:~/rubyprojects$ ruby demo_catchthrow.rb
Name: Ruby on Ruby
Age: 5
Sex: !
Name:test

3.17.5 Class Exception

异常类:

  • Interrupt
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

还有一种异常,Fatal, 不过Ruby解释器只是内部使用此类。 

若是咱们本身建立异常类,须要是Exception 或它的派生类的子类。

例如

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      @reason = reason
   end
end

使用以上自定义类:

File.open(path, "w") do |file|
begin
   # Write out the data ...
rescue
   # Something went wrong!
   raise FileSaveError.new($!)
end
end