ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# Ruby 输入&输出 > 原文: [https://zetcode.com/lang/rubytutorial/io/](https://zetcode.com/lang/rubytutorial/io/) 在 Ruby 教程的这一部分中,我们将讨论 Ruby 中的输入&输出操作。 输入是程序从键盘,文件或其他程序读取的任何数据。 输出是程序产生的数据。 输出可能会转到屏幕,文件或其他程序。 输入&输出是一个大话题。 我们提出一些示例,以使您对该主题有一个总体了解。 Ruby 中的几个类具有执行输入&输出操作的方法。 例如`Kernel`,`IO`,`Dir`或`File`。 ## Ruby 输出到控制台 Ruby 有几种方法可以在控制台上打印输出。 这些方法是`Kernel`模块的一部分。 `Kernel`的方法可用于 Ruby 中的所有对象。 ```ruby #!/usr/bin/ruby print "Apple " print "Apple\n" puts "Orange" puts "Orange" ``` `print`和`puts`方法在控制台上产生文本输出。 两者之间的区别在于后者添加了新的换行符。 ```ruby print "Apple " print "Apple\n" ``` 打印方法将两个连续的`"Apple"`字符串打印到终端。 如果要创建新行,则必须显式包含换行符。 换行符为`\n`。 在后台,`print`方法实际上调用了要打印对象的`to_s`方法。 ```ruby puts "Orange" puts "Orange" ``` `puts`方法将两个字符串打印到控制台。 每个人都有自己的路由。 该方法自动包括换行符。 ```ruby $ ./printing.rb Apple Apple Orange Orange ``` 这是`printing.rb`脚本文件的输出。 根据 Ruby 文档,`print`方法与`$stdout.print`等效。 `$stdout`是保存标准输出流的全局变量。 ```ruby #!/usr/bin/ruby $stdout.print "Ruby language\n" $stdout.puts "Python language" ``` 我们使用`$stdout`变量打印两行。 Ruby 还有另外三种打印输出的方法。 ```ruby #!/usr/bin/ruby p "Lemon" p "Lemon" printf "There are %d apples\n", 3 putc 'K' putc 0xA ``` 在示例中,我们介绍了`p`,`printf`和`putc`方法。 ```ruby p "Lemon" ``` `p`在打印对象时调用`inspect`方法。 该方法对于调试很有用。 ```ruby printf "There are %d apples\n", 3 ``` `printf`方法从 C 编程语言中是众所周知的。 它启用字符串格式。 ```ruby putc 'K' putc 0xA ``` `putc`方法将一个字符打印到控制台。 第二行打印换行符。 `0xA`是换行符的十六进制代码。 ```ruby $ ./printing3.rb "Lemon" "Lemon" There are 3 apples K ``` 这是`printing3.rb`程序的输出。 使用内核方法将数据打印到控制台是一个快捷方式:一种打印数据的简便方法。 以下示例显示了一种将数据打印到终端的更正式的方法。 ```ruby ios = IO.new STDOUT.fileno ios.write "ZetCode\n" ios.close ``` 在示例中,我们打开一个标准输出流,并将一个字符串写入其中。 ```ruby ios = IO.new STDOUT.fileno ``` `new`方法返回一个我们可以向其写入数据的流。 该方法采用数字文件描述符。 `STDOUT.fileno`为我们提供了标准输出流的文件描述符。 我们也可以简单地写 2。 ```ruby ios.write "ZetCode\n" ``` 我们向打开的流中写入一个字符串。 ```ruby ios.close ``` 输入流已关闭。 在 Unix 系统上,标准终端输出连接到名为`/dev/tty`的特殊文件。 通过打开并写入,我们将写入控制台。 ```ruby #!/usr/bin/ruby fd = IO.sysopen "/dev/tty", "w" ios = IO.new(fd, "w") ios.puts "ZetCode" ios.close ``` 一个小的例子,我们写入`/dev/tty`文件。 这仅适用于 Unix。 ```ruby fd = IO.sysopen "/dev/tty", "w" ``` `sysopen`方法打开给定路径,并返回基础文件描述符号。 ```ruby ios = IO.new(fd, "w") ``` 文件描述符号用于打开流。 ```ruby ios.puts "ZetCode" ios.close ``` 我们向流中写入一个字符串并将其关闭。 ## Ruby 从控制台读取输入 在本节中,我们将创建一些代码示例,这些示例将处理从控制台读取的内容。 `$stdin`是一个全局变量,其中包含标准输入的流。 它可用于从控制台读取输入。 ```ruby #!/usr/bin/ruby inp = $stdin.read puts inp ``` 在上面的代码中,我们使用`read`方法从控制台读取输入。 ```ruby inp = $stdin.read ``` `read`方法从标准输入读取数据,直到到达文件末尾。 通过在 Unix 上按`Ctrl + D`以及在 Windows 上按`Ctrl + Z`可以产生 EOF。 ```ruby $ ./reading.rb Ruby language Ruby language ``` 当我们启动不带参数的程序时,脚本将从用户读取数据。 读取直到我们按 `Ctrl + D` 或 `Ctrl + Z` 为止。 ```ruby $ echo "ZetCode" | ./reading.rb ZetCode $ ./input.rb < stones Garnet Topaz Opal Amethyst Ruby Jasper Pyrite Malachite Quartz ``` 如果我们进行一些重定向,脚本可以从另一个程序或文件中读取数据。 从控制台读取数据的常用方法是使用`gets`方法。 ```ruby #!/usr/bin/ruby print "Enter your name: " name = gets puts "Hello #{name}" ``` 我们使用`gets`方法从用户读取一行。 ```ruby name = gets ``` `gets`方法从标准输入读取一行。 数据被分配给名称变量。 ```ruby puts "Hello #{name}" ``` 我们已读取的数据将打印到控制台。 我们使用插值将变量包括在字符串中。 ```ruby $ ./readline.rb Enter your name: Jan Hello Jan ``` 样本输出。 在以下两个脚本中,我们将讨论`chomp`方法。 这是一个字符串方法,可从字符串末尾删除空格。 在执行输入操作时很有用。 方法名称和用法来自 Perl 语言。 ```ruby #!/usr/bin/ruby print "Enter a string: " inp = gets puts "The string has #{inp.size} characters" ``` 我们从用户那里读取一个字符串,然后计算输入字符串的长度。 ```ruby $ ./nochomp.rb Enter a string: Ruby The string has 5 characters ``` 消息说该字符串有 5 个字符。 这是因为它也计入换行符。 为了获得正确的答案,我们需要删除换行符。 这是`chomp`方法的工作。 ```ruby #!/usr/bin/ruby print "Enter a string: " inp = gets.chomp puts "The string has #{inp.size} characters" ``` 这次我们使用`chomp`方法剪切换行符。 ```ruby $ ./chomp.rb Enter a string: Ruby The string has 4 characters ``` Ruby 字符串确实有 4 个字符。 ## Ruby 文件 从正式的 Ruby 文档中,我们了解到`IO`类是 Ruby 中所有输入和输出的基础。 `File`类是`IO`类的唯一子类。 这两个类别紧密相关。 ```ruby #!/usr/bin/ruby f = File.open('output.txt', 'w') f.puts "The Ruby tutorial" f.close ``` 在第一个示例中,我们打开一个文件并向其中写入一些数据。 ```ruby f = File.open('output.txt', 'w') ``` 我们以写模式打开文件`"output.txt"`。 `open`方法返回一个 io 流。 ```ruby f.puts "The Ruby tutorial" ``` 我们使用上面打开的流来写入一些数据。 `puts`方法也可以用于将数据写入文件。 ```ruby f.close ``` 最后,流关闭。 ```ruby $ ./simplewrite.rb $ cat output.txt The Ruby tutorial ``` 我们执行脚本并显示`output.txt`文件的内容。 我们将有一个类似的示例,该示例将展示其他有效的方法。 ```ruby #!/usr/bin/ruby File.open('langs', 'w') do |f| f.puts "Ruby" f.write "Java\n" f << "Python\n" end ``` 如果`open`方法之后有一个块,则 Ruby 将打开的流传递到该块。 在该块的末尾,文件将自动关闭。 ```ruby f.puts "Ruby" f.write "Java\n" f << "Python\n" ``` 我们使用三种不同的方法写入文件。 ```ruby $ ./simplewrite2.rb $ cat langs Ruby Java Python ``` 我们执行脚本并检查`langs`文件的内容。 在第二个示例中,我们显示`File`类的一些方法。 ```ruby #!/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`的新文件,并调用一些方法。 ```ruby puts File.exists? 'tempfile' ``` `exists?`方法检查具有给定名称的文件是否已经存在。 该行返回`false`,因为我们尚未创建文件。 ```ruby f = File.new 'tempfile', 'w' ``` 文件已创建。 ```ruby puts File.mtime 'tempfile' ``` `mtime`方法为我们提供了文件的最后修改时间。 ```ruby puts f.size ``` 我们确定文件大小。 由于尚未写入文件,因此该方法返回 0。 ```ruby File.rename 'tempfile', 'tempfile2' ``` 最后,我们使用`rename`方法重命名文件。 ```ruby $ ./testfile.rb false 2011-11-05 16:19:36 +0100 0 ``` 这是一个示例输出。 接下来,我们将从磁盘上的文件中读取数据。 ```ruby #!/usr/bin/ruby f = File.open("stones") while line = f.gets do puts line end f.close ``` 这是一个简单的脚本,它将打开一个名为`stone`的文件,并将其内容逐行打印到终端。 ```ruby f = File.open("stones") ``` 我们打开一个`stones`文件。 默认模式是读取模式。 `stones`文件包含九个有价值的宝石名称,每个名称都位于单独的行上。 ```ruby while line = f.gets do puts line end ``` `gets`方法从 I/O 流中读取一行。 当我们到达文件末尾时,`while`块结束。 ```ruby $ ./readlines2.rb Garnet Topaz Opal Amethyst Ruby Jasper Pyrite Malachite Quartz ``` 这是示例的输出。 下一个示例将从文件中读取数据。 ```ruby #!/usr/bin/ruby fname = 'alllines.rb' File.readlines(fname).each do |line| puts line end ``` 该脚本显示了读取文件内容的另一种方法。 该代码示例将在终端上打印其自己的代码。 ```ruby File.readlines(fname).each do |line| puts line end ``` `readlines`从指定文件读取所有行,并以数组形式返回它们。 我们使用`each`方法遍历数组并将行打印到终端。 ```ruby $ ./alllines.rb #!/usr/bin/ruby fname = 'alllines.rb' File.readlines(fname).each do |line| puts line end ``` 示例的输出。 ## Ruby 目录 在本节中,我们使用目录。 我们有一个`Dir`类,可以在 Ruby 中使用目录。 ```ruby #!/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`类的四种方法。 ```ruby Dir.mkdir "tmp" ``` `mkdir`方法创建一个名为`tmp`的新目录。 ```ruby puts Dir.exists? "tmp" ``` 使用`exists?`方法,我们检查文件系统中是否存在具有给定名称的目录。 ```ruby puts Dir.pwd ``` `pwd`方法打印当前工作目录。 这是我们启动脚本的目录。 ```ruby Dir.chdir '..' ``` `chdir`方法更改到另一个目录。 `..`目录是当前工作目录的父目录。 ```ruby Dir.rmdir "tmp" puts Dir.exists? "tmp" ``` 最后,我们使用`rmdir`方法删除目录。 这次`exists?`方法返回`false`。 ```ruby $ ./dirs.rb true /home/vronskij/programming/ruby/io /home/vronskij/programming/ruby/io/tmp /home/vronskij/programming/ruby/io false ``` 这是示例的输出。 在第二个示例中,我们检索目录的所有条目,包括其文件和子目录。 ```ruby #!/usr/bin/ruby fls = Dir.entries '.' puts fls.inspect ``` `entries`方法返回给定目录的所有条目。 ```ruby fls = Dir.entries '.' puts fls.inspect ``` 我们得到当前目录的文件和目录数组。 `.`字符在此上下文中表示当前工作目录。 `inspect`方法为我们提供了更可读的数组表示形式。 ```ruby $ ./allfiles.rb ["putc.rb", "simplewrite.rb", "readlines2.rb", "fileexists.rb~" ... ``` 在输出中,我们可以看到文件和目录的数组。 第三个示例使用主目录。 计算机中的每个用户都有一个分配给他的唯一目录。 它称为主目录。 在这里,他可以放置文件并创建自己的目录层次结构。 ```ruby #!/usr/bin/ruby puts Dir.home puts Dir.home 'root' ``` 该脚本打印两个主目录。 ```ruby puts Dir.home ``` 如果未指定用户名,则返回当前用户的主目录。 当前用户是脚本文件的所有者。 有人启动了脚本。 ```ruby puts Dir.home 'root' ``` 在这里,我们打印特定用户的主目录:在本例中为超级用户。 ```ruby $ ./homedir.rb /home/vronskij /root ``` 这是一个示例输出。 ## Ruby 执行外部程序 Ruby 有几种执行外部程序的方法。 我们将处理其中一些问题。 在我们的示例中,我们将使用众所周知的 Linux 命令。 Windows 或 Mac 的阅读器可以使用特定于其系统的命令。 ```ruby #!/usr/bin/ruby data = system 'ls' puts data ``` 我们调用`ls`命令列出目录内容。 ```ruby data = system 'ls' ``` `system`命令在子 Shell 中执行外部程序。 该方法属于`Kernel` Ruby 模块。 ```ruby $ ./system.rb allfiles.rb characters.rb fileexists.rb homedir.rb~ ... ``` This is a sample output. 我们展示了另外两种在 Ruby 中运行外部程序的方式。 ```ruby #!/usr/bin/ruby out = `pwd` puts out out = %x[uptime] puts out out = %x[ls | grep 'readline'] puts out ``` 要运行外部程序,我们可以使用反引号`` ` ``或`%x[]`字符。 ```ruby out = `pwd` ``` 在这里,我们使用反引号执行`pwd`命令。 该命令返回当前工作目录。 ```ruby out = %x[uptime] ``` 在这里,我们获得`uptime`命令的输出,该命令指示系统运行了多长时间。 ```ruby out = %x[ls | grep 'readline'] ``` 我们也可以结合使用命令。 ```ruby $ ./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~ ``` This is a sample output. 我们可以使用`open`方法执行命令。 该方法属于`Kernel`模块。 它创建一个连接到给定流,文件或子流程的 IO 对象。 如果要连接到子进程,请使用管道字符`|`来启动`open`的路径。 ```ruby #!/usr/bin/ruby f = open("|ls -l |head -3") out = f.read puts out f.close puts $?.success? ``` 在示例中,我们打印`ls -l | head -3`命令的结果。 这两个命令的组合返回`ls -l`命令的前三行。 我们还检查子进程的状态。 ```ruby f = open("|ls -l |head -3") ``` 我们连接到由这两个命令创建的子流程。 ```ruby out = f.read puts out ``` 我们从子流程读取并打印数据。 ```ruby f.close ``` 我们关闭文件处理器。 ```ruby puts $?.success? ``` `$?`是一个特殊的 Ruby 变量,它设置为最后执行的子进程的状态。 如果子进程以 OK 结束,则`success?`方法返回`true`。 ```ruby $ ./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 ``` This is a sample output. ## Ruby 重定向标准输出 Ruby 具有用于标准输入,标准输出和标准错误输出的预定义全局变量。 `$stdout`是标准输出的变量的名称。 ```ruby #!/usr/bin/ruby $stdout = File.open "output.log", "a" puts "Ruby" puts "Java" $stdout.close $stdout = STDOUT puts "Python" ``` 在上面的示例中,我们将标准输出重定向到`output.log`文件。 ```ruby $stdout = File.open "output.log", "a" ``` 此行创建一个新的标准输出。 现在,标准输出将流到`ouput.log`文件。 该文件以附加模式打开。 如果该文件尚不存在,则会创建它。 否则,它将被打开并将数据写入文件的末尾。 ```ruby puts "Ruby" puts "Java" ``` 我们打印两个字符串。 字符串将不会像往常一样显示在终端中。 相反,它们将被附加到`output.log`文件中。 ```ruby $stdout.close ``` 处理器已关闭。 ```ruby $stdout = STDOUT puts "Python" ``` 我们使用预定义的标准常量`STDOUT`重新创建正常的标准输出。 `"Python"`字符串被打印到控制台。 在 Ruby 教程的这一部分中,我们使用 Ruby 进行输入和输出操作。