Ruby 中的输入 & 输出
最后修改于 2023 年 10 月 18 日
在本 Ruby 教程中,我们将讨论 Ruby 中的输入 & 输出操作。输入是程序读取的任何数据,无论是来自键盘、文件还是其他程序。输出是程序产生的数据。输出可以发送到屏幕、文件或另一个程序。
输入 & 输出是一个很大的话题。我们提供了一些例子,让您对这个主题有一个大致的了解。Ruby 中的几个类有用于执行输入 & 输出操作的方法。例如 Kernel
、IO
、Dir
或 File
。
Garnet Topaz Opal Amethyst Ruby Jasper Pyrite Malachite Quartz
一些例子使用了这个文件。
Ruby 写入控制台
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
使用内核方法将数据打印到控制台是一种快捷方式:一种方便的打印数据的方式。下面的例子展示了一种更正式的将数据打印到终端的方式。
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
我们将一个字符串写入流并关闭它。
Ruby 从控制台读取输入
在本节中,我们创建了一些处理从控制台读取的代码示例。
$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.txt 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}"
我们读取的数据被打印到控制台。我们使用字符串插值在字符串中包含该变量。
$ ./read_input.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"
我们从用户读取一个字符串,并计算输入字符串的长度。
$ ./no_chomp.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 文件
从 Ruby 官方文档中我们了解到,IO
类是 Ruby 中所有输入和输出的基础。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
方法返回一个 io 流。
f.puts "The Ruby tutorial"
我们使用上面打开的流来写入一些数据。puts
方法也可以用于将数据写入文件。
f.close
最后,流被关闭。
$ ./simple_write.rb $ cat output.txt The Ruby tutorial
我们执行脚本并显示 output.txt
文件的内容。
我们有一个类似的例子,展示了其他方法的操作。
#!/usr/bin/ruby File.open('langs.txt', '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"
我们使用三种不同的方法写入文件。
$ ./simple_write2.rb $ cat langs.txt Ruby Java Python
我们执行脚本并检查 langs
文件的内容。
在第二个例子中,我们展示了 File
类的几个方法。
#!/usr/bin/ruby puts File.exist? 'tempfile' f = File.new 'tempfile', 'w' puts File.mtime 'tempfile' puts f.size File.rename 'tempfile', 'tempfile2' f.close
本例创建了一个名为 tempfile
的新文件并调用了一些方法。
puts File.exist? 'tempfile'
exist?
方法检查具有给定名称的文件是否已经存在。该行返回 false,因为我们尚未创建文件。
f = File.new 'tempfile', 'w'
文件已创建。
puts File.mtime 'tempfile'
mtime
方法为我们提供了文件的最后修改时间。
puts f.size
我们确定文件大小。该方法返回 0,因为我们还没有写入文件。
File.rename 'tempfile', 'tempfile2'
最后,我们使用 rename
方法重命名该文件。
$ ./testfile.rb false 2020-09-14 15:54:13 +0200 0
这是一个示例输出。
接下来,我们从磁盘上的文件中读取数据。
#!/usr/bin/ruby f = File.open("stones.txt") while line = f.gets do puts line end f.close
该示例打开一个名为 stones.txt
的文件,并将其内容逐行打印到终端。
f = File.open("stones.txt")
我们打开一个 stones
文件。默认模式是读取模式。stones
文件包含九个有价值的石头名称,每个名称都在单独的行上。
while line = f.gets do puts line end
gets
方法从 I/O 流中读取一行。当到达文件末尾时,while 块结束。
$ ./read_file.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
方法遍历数组,并将这些行打印到终端。
$ ./all_lines.rb #!/usr/bin/ruby fname = 'alllines.rb' File.readlines(fname).each do |line| puts line end
Ruby 目录
在本节中,我们使用目录。我们有一个 Dir
类来处理 Ruby 中的目录。
#!/usr/bin/ruby Dir.mkdir "tmp" puts Dir.exist? "tmp" puts Dir.pwd Dir.chdir "tmp" puts Dir.pwd Dir.chdir '..' puts Dir.pwd Dir.rmdir "tmp" puts Dir.exist? "tmp"
在脚本中,我们使用了 Dir
类的四个方法。
Dir.mkdir "tmp"
mkdir
方法创建一个名为 tmp
的新目录。
puts Dir.exist? "tmp"
使用 exist?
方法,我们检查具有给定名称的目录是否存在于文件系统中。
puts Dir.pwd
pwd
方法打印当前工作目录。这是我们启动脚本的目录。
Dir.chdir '..'
chdir
方法更改为另一个目录。..
目录是当前工作目录的父目录。
Dir.rmdir "tmp" puts Dir.exist? "tmp"
最后,我们使用 rmdir
方法删除一个目录。这次 exist?
方法返回 false。
在第二个例子中,我们检索一个目录的所有条目,包括其文件和子目录。
#!/usr/bin/ruby fls = Dir.entries '.' puts fls.inspect
entries
方法返回给定目录的所有条目。
fls = Dir.entries '.' puts fls.inspect
我们获取当前目录的文件和目录的数组。.
字符表示此上下文中的当前工作目录。inspect
方法为我们提供了数组的更易读的表示形式。
第三个例子使用主目录。计算机中的每个用户都有一个为其分配的唯一目录。这被称为主目录。这是他可以放置文件并创建自己的目录层次结构的地方。
#!/usr/bin/ruby puts Dir.home puts Dir.home 'root'
该脚本打印了两个主目录。
puts Dir.home
如果我们没有指定用户名,则会返回当前用户的主目录。当前用户是脚本文件的所有者。某个启动了脚本的人。
puts Dir.home 'root'
在这里,我们打印了特定用户的主目录:在我们的例子中,是超级用户。
$ ./homedir.rb /home/janbodnar /root
这是一个示例输出。
Ruby 执行外部程序
Ruby 有几种执行外部程序的方法。我们处理其中的一些方法。在我们的例子中,我们使用了众所周知的 Linux 命令。Windows 或 Mac 用户可以使用特定于其系统的命令。
#!/usr/bin/ruby data = system 'ls' puts data
我们调用了 ls
命令,该命令列出了目录内容。
data = system 'ls'
system
命令在子 shell 中执行一个外部程序。该方法属于 Kernel
Ruby 模块。
我们展示了在 Ruby 中运行外部程序的其他两种方法。
#!/usr/bin/ruby out = `pwd` puts out out = %x[uptime] puts out out = %x[ls | grep 'readline'] puts out
要运行外部程序,我们可以使用反引号 ``
或 %x[]
字符。
out = `pwd`
在这里,我们使用反引号执行了 pwd
命令。该命令返回当前工作目录。
out = %x[uptime]
在这里,我们获取了 uptime
命令的输出,该命令告诉我们系统运行了多长时间。
out = %x[ls | grep 'readline']
我们也可以使用命令的组合。
我们可以使用 open
方法执行命令。该方法属于 Kernel
模块。它创建一个连接到给定流、文件或子进程的 IO 对象。如果我们要连接到子进程,我们从 open
的路径开始使用管道字符 |
。
#!/usr/bin/ruby f = open("|ls -l |head -3") out = f.read puts out f.close puts $?.success?
在本例中,我们打印了 ls -l | head -3
命令的结果。这两个命令的组合返回了 ls -l
命令的前三行。我们还检查了子进程的状态。
f = open("|ls -l |head -3")
我们连接到这两个命令创建的子进程。
out = f.read puts out
我们从子进程读取并打印数据。
f.close
我们关闭文件处理程序。
puts $?.success?
$?
是一个特殊的 Ruby 变量,它被设置为最后一个已执行的子进程的状态。如果子进程运行 OK,则 success?
方法返回 true。
Ruby 重定向标准输出
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" 被打印到控制台。
在本 Ruby 教程中,我们学习了 Ruby 中的输入和输出操作。