本文主要是介绍Basic Input and Output,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一开始时你会以为 Ruby 提供了两组独立的 IO
例程。第一种是基本接口,目前为止我们一直都是使用它。
print "Enter your name: "
name = gets
在 Kernel
模块中实现了一组完整的 IO 相关方法,比如
get
,open
,print
,printf
,putc
,puts
,readline
,readlines
和 test
,这些方法使得编写 Ruby
程序更加方便和简洁。这些方法通常对标准输入输出进行 I/O
操作,这有利于它们编写过滤器。你可以从 411 页开始查看文档。
第二种方式就是通过 IO
对象完成很多自定义的控制。
IO 对象是什么?
Ruby 定义了单独一个基础类—— IO
,它可以操作输入输出。File
和 BasicSocket
都是它的子类,并在它的基础上实现了很多个性化的操作,不过原则是不变的。一个
IO
对象就是一个在 Ruby
程序和外部资源之间的双向通道。(对于那些想了解实现细节的人来说,这个双向通道意味着一个单独的
IO
对象有时需要管理不止一个操作系统的文件描述符。比如,如果你开启了一对管道,那一个
IO 对象就包含一个读管道和一个写管道。)也就是说一个 IO
对象比你看到的包含更多,不过在最后你可以轻松的写入其中或从其中读取。
在这章中,我们会专注于 IO 类以及它比较常用的子类—— File
类。对于在网络中使用
socket 类的细节可以看从 469 页开始的部分。
打开和关闭文件
你也许希望可以用 File.new
创建新的文件对象。
aFile = File.new("testfile", "r")# ... process the fileaFile.close
你通过只读,只写或读写的方式创建 File
对象,不同的创建文件模式根据模式字符串决定(例子中我们是通过 r
确定以只读模式打开 testfile
文件的)。可使用的模式列表在
326
页。当创建文件时你也可以随意指定它的权限,关于这里的细节可以查阅 303
页的内容。在打开文件后你便可以操作它,可以读或写自己需要的数据。最后,出于对软件的负责我们还应该关闭文件,以确认缓冲数据都已经完全写入文件并且相关资源都得到释放。
不过 Ruby 也可以使你的生活更加简单。File.open
也可以打开文件。在常规使用上它与 File.new
的行为相似。但是,如果有关联代码块需要调用的话 open
会有些区别。与返回新的 File
对象不同,它将调用代码块并以刚打开的 File
作为参数。当代码块退出时文件也将自动关闭。
File.open("testfile", "r") do |aFile|# ... process the fileend
读写文件
与基本的 I/O 类似的方法对文件对象也是有用的。所以,gets
是从标准输入读取一行内容,aFile.gets
也是从文件对象 aFile
中读取一行内容。
不过 I/O
对象喜欢一组额外的访问方法,这些方法的目的是使我们的工作更加轻松。
迭代器读取文件
和用常规循环从 IO 流中读取数据一样,你也可以使用多种 Ruby
的迭代器。IO#each_byte
会从 IO 对象中连续读取 8
位字节并调用代码块。
aFile = File.new("testfile")
aFile.each_byte {|ch| putc ch; putc ?. }
结果是:
T.h.i.s. .i.s. .l.i.n.e. .o.n.e.
.T.h.i.s. .i.s. .l.i.n.e. .t.w.o.
.T.h.i.s. .i.s. .l.i.n.e. .t.h.r.e.e.
.A.n.d. .s.o. .o.n.......
.
IO#each_line
从文件中读取下一行内容并调用代码块。下面的例子中我们会用 String#dump
让原始的换行符可见,所以你会知道我们并没有说谎。
aFile.each_line {|line| puts "Got #{line.dump}" }
结果是:
Got "This is line one\n"
Got "This is line two\n"
Got "This is line three\n"
Got "And so on...\n"
你可以将任意字符串作为行分隔符向 each_line
传参,转入内容也会按照相应的分隔符进行分隔,最后还会将每行数据至结束字符间的内容返回。这就是你可以在上个例子中看见
「\n」输出的原因。下面的例子中,我们要用
「e」作为行分隔符。
aFile.each_line("e") do |line|puts "Got #{ line.dump }"
end
结果是:
Got "This is line"
Got " one"
Got "\nThis is line"
Got " two\nThis is line"
Got " thre"
Got "e"
Got "\nAnd so on...\n"
如果你结合迭代器和使用代码块时文件会自动关闭的特点就会产生
IO.foreach
。这个方法需要将 I/O
资源的名称作为入参,将其打开并调用迭代器对文件的每行内容读取,再自动关闭文件。
IO.foreach("testfile") { |line| puts line }
结果是:
This is line one
This is line two
This is line three
And so on...
或者如果你喜欢,你也可以将文件内容收集为行的数组。
arr = IO.readlines("testfile")
arr.length »4
arr[0] »"This is line one\n"
不要忘记 I/O
在非必然世界中不一定有必然的结果,有时许多错误情况都会导致异常,你应该为捕捉它们并做出合适的反应作好准备。
写入文件
我们所写的例子中几乎都调用了 puts
和 print
方法,并且传递任意的对象,然后只能依赖 Ruby
会做正确的行为(当然,它确实也做到了)。不过它是怎么准确做到的呢?
答案非常简单。除了少量的例外情况,每个传递给 puts
和 print
的对象都是通过调用对象的 to_s
方法转换为字符串的。如果由于某些原因 to_s
方法没有返回有效字符串,将会创建一个包含对象类名及 id
的字符串返回,像 <ClassName:0x123456>
这样。
异常情况也比较常见。nil
对象会作为字符串「nil」打印,传参给 puts
的数组将对其中的每个元素分别打印。
如果你想输出二进制数据又不希望 Ruby
弄乱它,需要怎么做?一般情况下你可以用 IO#print
并将包含字节码的字符串传入。不过你也可以通过低级别的输入输出例程完成此功能,可以查阅
335 页的 IO#sysread
和 IO#syswrite
方法。
首先你要怎样将二进制数据转换为字符串呢?有两个类似功能的方法,一种是将字节码按字节码的方式输入,另一种是通过
Array#pack
方法。
str = "" »""
str << 1 << 2 << 3 »"\001\002\003"
[ 4,str 5, 6 ].pack("c*") »"\004\005\006"
但我忘记了 C++ 输入输出流
有时个人品味是没法解释的。不过,既然可以通过 <<
操作符将对象附加至 Array
,也可以将对象到输出的 IO 流中。
endl = "\n"
$stdout << 99 << " red balloons" << endl
结果是:
99 red balloons
再说明一下,<<
方法会在将参数传递之前通过它们的 to_s
方法将它们转换为字符串。
与网络交流
无论是低级别还是高级别的网络协议的使用上,Ruby
都表现出了流畅性。
对于喜欢在网络级别上钻研的人,Ruby 为他们在 socket
库中准备了一系列相关的类。这些类可以帮助你访问 TCP,UDP,SOCKS
及 Unix
主要网络接口,以及架构上支持的任何网络接口类型。库中也提供了帮助类,可以使用帮助类很方便地编写服务器。下面是一个简单的例子,我们通过
finger 协议从本地机器上获得关于「oracle」用户的相关信息。
require 'socket'
client = TCPSocket.open('localhost', 'finger')
client.send("oracle\n", 0) # 0 means standard packet
puts client.readlines
client.close
结果是:
Login: oracle Name: Oracle installation
Directory: /home/oracle Shell: /bin/bash
Never logged in.in
No Mail.
No Plan.
在更高层中,net 库模块提供了相关的处理类对应用层协议(一般有 FTP, HTTP,
POP, SMTP, 和网络)进行操作。相关文档可从 482
页开始查阅。例如,下面的程序将列举 Pragmatic Programmer
主页显示的图片。
require 'net/http'h = Net::HTTP.new('www.pragmaticprogrammer.com', 80)
resp, data = h.get('/index.html', nil)
if resp.message == "OK"data.scan(/<img src="(.*?)"/) { |x| puts x }
end
结果是:
images/title_main.gif
images/dot.gif
images/dot.gif
images/dot.gif
images/aafounders_70.jpg
images/pp_cover_thumb.png
images/ruby_cover_thumb.png
images/dot.gif
images/dot.gif
本文翻译自《Programming Ruby》,主要目的是自己学习使用,文中翻译不到位之处烦请指正,如需转载请注明出处
本章原文为 Basic Input and
Output
这篇关于Basic Input and Output的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!