Ruby的输入&输出
这部分的教程我们讨论Ruby的输入和输出操作。输入是程序从键盘、文件或者其他程序读取数据。输出是程序产生数据。可以输出到屏幕、文件或者其他程序。
输入&输出是一个大的话题。稍后我们通过一些例子来大概介绍一下这个主题。Ruby中的一些类有些方法会执行输入&输出操作。例如Kernel、IO、Dir或者File。
输出到终端
Ruby有一些在终端上打印输出的方法。这些方法是Kernel模块的一部分。Kernel模块的方法对于所有的Ruby对象都是有效的。
#!/usr/bin/ruby
print “Apple “
print “Apple\n”
puts “Orange”
puts “Orange”
print和puts方法会将文本输出到终端。它们的不同是会在最后加上一个换行符。
print “Apple “
print “Apple\n”
print在终端上打印两个连续的”Apple”字符串。如果我们想换一行,我们就必须显示的包含一个换行符。换行符是’\n’。print方法实际上是调用了对象的to_s方法。
puts “Orange”
puts “Orange”
puts方法在终端上打印两个字符串。每一个都各在一行。这个方法会自己添加换行符。
$ ./printing.rb
Apple Apple
Orange
Orange
printing.rb脚本的输出结果。
根据Ruby的文档,print方法与$stdout.print是等效的。$stdout是全局变量,保存的标准输出流。
#!/usr/bin/ruby
$stdout.print “Ruby language\n”
$stdout.puts “Python language”
我们使用$stdout变量打印两行内容。
Ruby有另外三种输出方法。
#!/usr/bin/ruby
p “Lemon”
p “Lemon”
printf “There are %d apples\n”, 3
putc ‘K’
putc 0xA
这个例子中,我们展示了p、printf和putc方法。
p “Lemon”
p会调用对象的inspect方法。这个方法对于调试很有用。
printf “There are %d apples\n”, 3
printf方法因C语言而出名。它能够将字符串格式化。
putc ‘K’
putc 0xA
putc方法在终端上打印一个字符。第二行是打印一个换行符。0xA是换行符的十六进制代码。
$ ./printing3.rb
“Lemon”
“Lemon”
There are 3 apples
K
printing3.rb的输出。
使用Kernel的方法在终端上打印数据是简短方便的方式。接下来的例子展示了更多在终端上打印数据的正式方法。
ios = IO.new STDOUT.fileno
ios.write “ZetCode\n”
ios.close
这个例子我们打开标准输出流并往其中写入字符串。
ios = IO.new STDOUT.fileno
new方法返回一个可写的数据流。这个方法传入一个文件描述符数字。STDOUT.fileno返回了标准输出流的文件描述符。我们也可以直接写2。
ios.write “ZetCode\n”
我们往打开的数据流写入字符串。
ios.close
关闭输出流。
在Unix系统中标准的终端输出是连接到一个特殊的文件/dev/tty。将其打开并写入数据,既是写到终端上。
#!/usr/bin/ruby
fd = IO.sysopen “/dev/tty”, “w”
ios = IO.new(fd, “w”)
ios.puts “ZetCode”
ios.close
写入到/dev/tty文件的一个例子。这仅能够在Unix上运行。
fd = IO.sysopen “/dev/tty”, “w”
sysopen方法打开指定目录的文件,返回最后的文件描述符。
ios = IO.new(fd, “w”)
文件描述符数字用于打开一个数据流。
ios.puts “ZetCode”
ios.close
往数据流中写入字符串然后关闭它。
从终端输入
这一节我们将创建一些处理输入的代码例子。
$stdin是一个全局变量保存了标准输入流。它可以用于从终端输入数据。
#!/usr/bin/ruby
inp = $stdin.read
puts inp
上面的代码,我们使用read方法从终端读取输入。
inp = $stdin.read
read方法从标准输入读取数据直到文件结尾。EOF在Unix中是使用Ctrl + D产生,在Windows中是Ctrl + Z。
$ ./reading.rb
Ruby language
Ruby language
我们启动了程序,这个脚本会读取数据直到我们按下Ctrl + D 或者 Ctrl + Z。
$ echo “ZetCode” | ./reading.rb
ZetCode
$ ./input.rb < stones
Garnet
Topaz
Opal
Amethyst
Ruby
Jasper
Pyrite
Malachite
Quartz
如果我们使用重定向,脚本可以从其他程序或者文件中读取数据。
通常从终端读取数据是使用gets方法。
#!/usr/bin/ruby
print “Enter your name: “
name = gets
puts “Hello #{name}”
使用gets方法读取用户输入的一行数据。
name = gets
gets方法从标准输入读取数据并分配给name变量。
puts “Hello #{name}”
打印输入的数据。
$ ./readline.rb
Enter your name: Jan
Hello Jan
输出结果。
接下来的两个脚本我们讨论chomp方法。它是字符串方法,用于移除字符串结尾的空白。当我们执行输入操作时它很有用。这个方法名和用法来自Perl语言。
#!/usr/bin/ruby
print “Enter a string: “
inp = gets
puts “The string has #{inp.size} characters”
读取一个用户输入的字符串,并计算它的长度。
$ ./nochomp.rb
Enter a string: Ruby
The string has 5 characters
这个提示表示了这个字符串有5个字符,因为它统计的换行符。
为了得到正确的结果,我们需要移除换行符。这正是chomp方法的作用。
#!/usr/bin/ruby
print “Enter a string: “
inp = gets.chomp
puts “The string has #{inp.size} characters”
这次我们使用chomp方法截掉了换行符。
$ ./chomp.rb
Enter a string: Ruby
The string has 4 characters
Ruby字符串有4个字符。
文件
从Ruby官方文档我们知道IO类是所有输入输出的基类。File类只是IO类的一个子类。这两个类是紧密相关的。
#!/usr/bin/ruby
f = File.open(‘output.txt’, ‘w’)
f.puts “The Ruby tutorial”
f.close
第一个例子我们打开一个文件并往里面写入一些数据。
f = File.open(‘output.txt’, ‘w’)
以写模式打开’output.txt’文件。open方法返回数据流。
f.puts “The Ruby tutorial”
往上面打开的数据流写入数据。puts方法也可用于往文件写入数据。
f.close
最后关闭数据流。
$ ./simplewrite.rb
$ cat output.txt
The Ruby tutorial
执行脚本并显示output.txt文件的内容。
以下是一个类似的例子显示了额外的方法。
#!/usr/bin/ruby
File.open(‘langs’, ‘w’) do |f|
f.puts “Ruby”
f.write “Java\n”
f << “Python\n”
end
如果open方法之后是一个代码块,Ruby会将打开的数据流传递给这个代码块。最后这个文件会自动关闭。
f.puts “Ruby”
f.write “Java\n”
f << “Python\n”
我们使用了三个方法写文件。
$ ./simplewrite2.rb
$ cat langs
Ruby
Java
Python
执行这个脚本并查看里面的内容。
第二个例子我们显示一些File类的方法。
#!/usr/bin/ruby
puts File.exists? ‘tempfile’
f = File.new ‘tempfile’, ‘w’
puts File.mtime ‘tempfile’
puts f.size
File.rename ‘tempfile’, ‘tempfile2’
f.close
这个例子创建了一个新文件’tempfile’并调用了一些方法。
puts File.exists? ‘tempfile’
exists?方法检查给定的文件是否存在。这行返回false,因为我们还没有创建这个文件。
f = File.new ‘tempfile’, ‘w’
创建文件。
puts File.mtime ‘tempfile’
mtime方法返回这个文件的最后修改时间。
puts f.size
查看文件的大小。这里返回0,因为我们还没有往文件写入数据。
File.rename ‘tempfile’, ‘tempfile2’
最后我们使用rename将文件重命名。
$ ./testfile.rb
false
2011-11-05 16:19:36 +0100
0
输出结果。
接下来我们从磁盘文件读取内容。
#!/usr/bin/ruby
f = File.open(“stones”)
while line = f.gets do
puts line
end
f.close
这是一个简单的脚本,打开stones文件并在终端上打印它的内容。
f = File.open(“stones”)
打开’stones’文件,默认是只读模式。
while line = f.gets do
puts line
end
gets方法从I/O数据流读取一行数据。当读到文件结尾时while代码块退出。
$ ./readlines2.rb
Garnet
Topaz
Opal
Amethyst
Ruby
Jasper
Pyrite
Malachite
Quartz
例子输出结果。
下一个例子将从文件读取数据。
#!/usr/bin/ruby
fname = ‘alllines.rb’
File.readlines(fname).each do |line|
puts line
end
这个脚本显示了另一个读取文件内容的方式。这个例子将它自己的代码打印在终端上。
File.readlines(fname).each do |line|
puts line
end
readlines读取指定文件的每一行内容,并作为数据返回。我们使用each方法遍历数组,并将其在终端上打印。
$ ./alllines.rb
#!/usr/bin/ruby
fname = ‘alllines.rb’
File.readlines(fname).each do |line|
puts line
end
输出结果。
目录
在这一节我们使用目录。Ruby中有一个Dir类可以操作目录。
#!/usr/bin/ruby
Dir.mkdir “tmp”
puts Dir.exists? “tmp”
puts Dir.pwd
Dir.chdir “tmp”
puts Dir.pwd
Dir.chdir ‘..’
puts Dir.pwd
Dir.rmdir “tmp”
puts Dir.exists? “tmp”
这个脚本我们使用了Dir类的四个方法。
Dir.mkdir “tmp”
mkdir方法创建一个新目录’tmp’。
puts Dir.exists? “tmp”
使用exists?方法检查一个目录是否存在。
puts Dir.pwd
pwd方法打印当前的工作目录。这是我们启动脚本的目录。
Dir.chdir ‘..’
chdir方法切换目录。’..’目录是当前工作目录的父目录。
Dir.rmdir “tmp”
puts Dir.exists? “tmp”
最后我们使用rmdir方法移除目录。这时exists?方法返回false。
$ ./dirs.rb
true
/home/vronskij/programming/ruby/io
/home/vronskij/programming/ruby/io/tmp
/home/vronskij/programming/ruby/io
false
例子的输出结果。
第二个例子我们检索目录所有的条目,包括文件和子目录。
#!/usr/bin/ruby
fls = Dir.entries ‘.’
puts fls.inspect
entries 方法返回指定目录的所有条目。
fls = Dir.entries ‘.’
puts fls.inspect
我们得到了当前目录下的文件和目录数组。’.’代表当前工作目录。inspect方法使得数组更加可读。
$ ./allfiles.rb
[“putc.rb”, “simplewrite.rb”, “readlines2.rb”, “fileexists.rb~” …
输出结果。
第三个例子使用了home目录。每个计算机用户都有一个分配给他的唯一的目录,称为home目录。它是用于存放用户自己的文件。
#!/usr/bin/ruby
puts Dir.home
puts Dir.home ‘root’
这个脚本打印两个home目录。
puts Dir.home
如果没有指定用户名则返回当前用户的home目录。当前用户是指定启动这个脚本文件的用户。
puts Dir.home ‘root’
这里我们指定了一个用户。
$ ./homedir.rb
/home/vronskij
/root
输出结果。
执行外部程序
Ruby有一些方式可以执行外部程序。我们的例子中我们使用了Linux中有名的命令。Windows或者Mac读取可以使用他们自己系统的命令。
#!/usr/bin/ruby
data = system ‘ls’
puts data
调用ls命令列出目录内容。
data = system ‘ls’
system命令在一个子shell中执行外部程序。这个方法是属于Kernel Ruby 模块的。
$ ./system.rb
allfiles.rb characters.rb fileexists.rb homedir.rb~ …
输出结果。
我们展示另外两个执行外部程序的方式。
#!/usr/bin/ruby
out = pwd
puts out
out = %x[uptime]
puts out
out = %x[ls | grep ‘readline’]
puts out
执行外部程序我们可以使用反引号`和%x[]字符。</p>
<pre><code>out =
pwd`
这里我们使用反引号执行pwd命令。这个命令返回当前的工作目录。
out = %x[uptime]
这里我得到uptime命令的输出,它显示系统运行了多久。
out = %x[ls | grep ‘readline’]
我们也可以使用复合命令。
$ ./system2.rb
/home/vronskij/programming/ruby/io
22:50:50 up 5:32, 1 user, load average: 0.46, 0.44, 0.45
readline.rb
readline.rb~
readlines2.rb
readlines2.rb~
输出结果。
我们可以使用open方法执行命令。这个方法是属于Kernel模块的。它创建一个IO对象连接到指定的数据流、文件或者子进程。如果我们想要连接到子进程,我们将打开路径以管道符(|)开头。
#!/usr/bin/ruby
f = open(“|ls -l |head -3”)
out = f.read
puts out
f.close
puts $?.success?
这个例子我们打印了ls -l | head -3命令的结果。我们也还检查了子进程的状态。
f = open(“|ls -l |head -3”)
连接到子进程。
out = f.read
puts out
读取并打印子进程的数据。
f.close
关闭文件句柄。
puts $?.success?
$?是一个特殊的变量,设置为上次执行过的子进程。如果子进程成功退出success?方法返回true。
$ ./system3.rb
total 148
-rwxr-xr-x 1 vronskij vronskij 57 2011-10-30 23:33 allfiles.rb
-rwxr-xr-x 1 vronskij vronskij 58 2011-10-30 23:33 allfiles.rb~
true
输出结果。
重定向标准输出
Ruby对标准输入、标准输出和标准错误输出都有预定义的全局变量。$stdout 是标准输出的变量名。
#!/usr/bin/ruby
$stdout = File.open “output.log”, “a”
puts “Ruby”
puts “Java”
$stdout.close
$stdout = STDOUT
puts “Python”
上面的例子我们将输出重定向到output.log文件。
$stdout = File.open “output.log”, “a”
这行创建一个新的标准输出。现在标准输出流向ouput.log文件。这个文件以追加方式打开,如果文件不存在则创建,否则打开并将数据追加到文件尾部。
puts “Ruby”
puts “Java”
打印两个字符串。这些字符串不会像平常一样在终端上显示了。而是追加到output.log文件中。
$stdout.close
关闭文件句柄。
$stdout = STDOUT
puts “Python”
使用预定义的常量STDOUT重新创建正常的标准输出。”Python”字符串在终端上打印。
这部分的教程我们使用了输入和输出操作。
原文地址: http://zetcode.com/lang/rubytutorial/io/
翻译:龙昌 admin@longchangjin.cn
完整教程:https://github.com/wusuopu/Ruby-tutorial