• 《Rubu基础教程第五版》第十七章笔记 IO类


    输入/输出的种类

    标准输入/输出

    程序在启动后会预先分配3个IO对象。

    标准输入

    标准输入是用于接收数据的IO对象。可以通过预定义常量STDIN调用IO对象,也可以通过全局变量$stdin引用IO对象。不指定接受者的gets方法等都会默认从$stdin中获取数据。标准输入最初与控制台关联,接收从键盘输入的内容。

    标准输出

    标准输出是用于输出数据的IO对象。可以通过预定义常量STDOUT调用IO对象,也可以用全局变量$stdout引用IO对象。不知道接受者的puts、print、printf等方法会默认将数据输出到$stdout。标准输出最初与控制台关联

    标准错误输出

    标准错误输出是用于输出警告、错误的IO对象。可以通过预定义常量STDERR调用IO对象,也可以用全局变量$stderr引用IO对象。用于显示警告信息的warn方法会将信息输出到$stderr。标准版错误输出最初与控制台关联

    代码

    3.times do |i|
      $stdout.puts "#{Random.rand}"
      STDERR.puts "已经输出了#{i+1}次"
    end
    

     通过一个标准输出,一个错误输出,只有标准输出会被写入文件。

    通过tty检查标准输入是否为屏幕的例子

    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ ruby tty.rb 
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin19/rbconfig.rb:229: warning: Insecure world writable dir /usr/local/opt/mysql@5.7/bin in PATH, mode 040777
    Stdin is a  TTY. 
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ echo | ruby tty.rb 
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin19/rbconfig.rb:229: warning: Insecure world writable dir /usr/local/opt/mysql@5.7/bin in PATH, mode 040777
    Stdin is not a TTY. 
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ ruby tty.rb < log.txt
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin19/rbconfig.rb:229: warning: Insecure world writable dir /usr/local/opt/mysql@5.7/bin in PATH, mode 040777
    Stdin is not a TTY. 
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat tty.rb 
    if $stdin.tty?
      print "Stdin is a  TTY. 
    "
    else
      print "Stdin is not a TTY. 
    "
    end
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ 
    

    文件的输入与输出

    通过IO类的子类File类可以进行文件的输入/输出操作。

    io = File.open(file [, mode[,perm]][, opt])

    io = open(file [, mode[,perm]][, opt])

    通过上面的方法可以获得一个io对象

    mode默认是"r",可以通过设定指定的值,模式跟Python中的open差不多

    File操作中,可以通过块变量传递给块。块执行完毕后,块变量引用的File对象也会自动关闭。像Python中的with open as f

    File.open("foo.txt") do |file|
      while line = file.gets
        ...    #执行逻辑
      end
    end
    

    file.closed?检查file对象是否关闭

    File.read(file,[, length [, offset]])

    不创建File对象,直接读取file里面的数据。length指定读取长度,offset指定从前面第几个字节开始读取数据。如忽略这些参数,程序会从头到位一次性读取文件内容

    File.binread(file,[, length [, offset]])

    二进制的方式读取文件

    FIle.write(file[,data[,offset]])

    不创建File对象,直接向file写入data。省略参数offset时,会将文件的全部内容替换为data,指定该参数时,则会将前面offset个字节写入文件,后面的数据则保持不变

    >> text = "Hello,Ruby!
    "
    => "Hello,Ruby!
    "
    >> File.write("hello.txt", text)
    => 12
    >> p File.read("hello.txt")
    "Hello,Ruby!
    "
    => "Hello,Ruby!
    "
    >> File.write("hello.txt", "12345", 5)
    => 5
    >> p File.read("hello.txt")
    "Hello12345!
    "
    => "Hello12345!
    "
    >> 
    

    File.binwrite(file[,data[,offset]])

    以二进制模式打开并写入file

    基本的输入/输出操作

    对于io对象的基本操作。

    输入操作 io.gets,io.each,io.each_line,io.readlines

    io.gets(rs) rs为分隔符,默认为" "

    这个方法就像逐行读取,默认读取的时候带 ,可以通过chmop!去除

    可以通过eof?去判断有没是否输入完毕

    io.each 与io.each_line返回的是一个枚举对象了

    irb(main):001:0> io = open("log.txt")
    => #<File:log.txt>
    irb(main):002:0> io.each.class
    => Enumerator
    irb(main):003:0> 
    

    io.reandline方案可以差异性读取所有数据,并返回将每行数据作为元素封装的数组。

    io.lineno

    使用gets方法、each_line方法逐行读取数据时,会自动记录读取的行数。这个行数可以通过lineno方法获取。

    io.each_char

    io.eache_char do |ch|

    ...

    end

    逐个字符地读取io中的数据并执行块,将读取的字符(String对象)作为块变量的传递

    io.each_byte

    逐个字节的读取io中的数据并启动块,将读取到的字节所对应的ASCII码以整数值的形式传递给块变量

    io.getc

    while ch = io.getc

    ...

    end

    只读取io中的一个字符。

    io.ungetc(ch)

    将参数ch指定的字符退回到io到输入缓冲区中.

    >> File.open("hello.txt") do |io|
    ?>   p io.getc
    >>   io.ungetc("h")
    >>   p io.gets
    >> end
    "H"
    "hello,Ruby.\n
    "
    => "hello,Ruby.\n
    "
    >> exit
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat hello.txt 
    Hello,Ruby.
    
    

     io.getbyte

    只读取io中的一个字节,以整数对象返回与得到的字节相对应的ASCII码。数据全部读取完后,再读取时会返回nil

    io.ungetbyte(byte)

    将参数byte指定的一个字节退出到输入缓冲区中。

    io.read(size)

    读取参数size中指定的大小的数据。不指定大小时,会一次性读取全部数据并返回

    File.open("hello.txt") do |io|
      p io.read(5)
      p io.read
    end
    

    输出操作

    io.puts在字符串末尾添加换行符后输出。指定多个参数时,会分别添加换行符。如果参数为String类以外的对象,则会调用to_s方法,将其转换为字符串后再输出

    irb(main):015:0> $stdout.puts "String", :Symbol, 1/100r
    String
    Symbol
    1/100
    => nil
    irb(main):016:0> 
    

    io.putc(ch)

    输出参数ch指定的字符编码所对应的字符,参数为字符串时输出首字符

    RR
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat stduout_putc.rb 
    $stdout.putc(82)
    $stdout.putc("Ruby")
    $stdout.putc("
    ")
    

     剩下还有 io.print, io.printf, io.write

    irb(main):001:0> size = $stdout.write("Hello.
    ")
    Hello.
    => 7
    irb(main):002:0> p size
    7
    => 7
    

    io<<str

    输出参数str指定的字符串。<<会返回接受者本身,因此可以像下面这样写

    io << "foo" << "bar" << "baz"

    文件指针

    我们用文件指针(file pointer)或者当前文件偏移量(current file offset)来表示IO对象的文件的位置。

    io.pos

    io.pos =(position)

    通过pos方法可以获得文件指针现在的位置。改变文件指针的位置用pos=方法

    "Hello"
    5
    "Hello,Ruby.
    "
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat io_pos.rb 
    File.open("hello.txt") do |io|
      p io.read(5)
      p io.pos
      io.pos = 0   # 初始到开头
      p io.gets
    end
    

    io.seek(offset, whence)

    whence用于指定office如何移动

    whence中指定的值

    IO::SEEK_SET    将文件指针移动到offset指定的位置      那就相当于 io.pos

    IO::SEEK_CUR   将offset视为相对于当前位置的偏移量位置来移动文件指针

    IO::SEEK_END   将offset指定为行对于文件末尾的偏移文职

    io.rewind

    "Hello"
    0
    "Hello,Ruby.
    "
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat io_rewind.rb 
    File.open("hello.txt") do |io|
      p io.read(5)
      p io.rewind        # 返回到文件的初始位置 ,pos =0
      p io.gets
    end
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ 
    

    io.truncate(size)

    按照参数size指定的大小截止文件。

    io.truncate(0)      # 将文件大小设为0

    io.truncate(io.pos)   # 删除当前文件指针以后的数据

    二进制模式与文本模式

    ruby默认会在各个平台对换行进行转换,如果不想进行转换,可以将状态切换成二进制模式

    File.open("foo.txt", "w") do |io|
      io.binmode    # 进入二进制模式
      io.write "Hello, world.
    "
    end
    

    缓冲

    即使对IO对象进行写入,结果叶不能并不一定马上就反应再控制台或者文件中。再使用write、print等方法操作IO对象时,程序内部会开辟除一定的空间来保存临时生成的数据副本

    这部分空间称为缓冲区。缓冲区里积累到一定量的数据后,就会进行输出处理,然后清空缓冲区

    使用缓冲区进行数据处理称为缓冲

    第1次: 0
    第2次: 0
    第3次: 0
    结束后: 15
    "aaaaaaaaaaaaaaa"
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat test_buffering1.rb 
    filename = "buffering.txt"
    File.open(filename, "w") do |file|
      3.times do |i|
        # 检查写入5次字节后的文件的大小
          file.write("a" * 5)
          puts "第#{i+1}次: #{File.size(filename)}"
      end
    end
    
    puts "结束后: #{File.size(filename)}"
    p File.read(filename)
    

    这样的好处可以减少频繁的硬盘读写

    io.flush

    第1次: 5
    第2次: 10
    第3次: 15
    结束后: 15
    "aaaaaaaaaaaaaaa"
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ cat test_buffering2.rb 
    filename = "buffering.txt"
    File.open(filename, "w") do |file|
      3.times do |i|
        # 检查写入5次字节后的文件的大小
          file.write("a" * 5)
          file.flush     # 立即输出缓存区的数据
          puts "第#{i+1}次: #{File.size(filename)}"
      end
    end
    
    puts "结束后: #{File.size(filename)}"
    p File.read(filename)
    shijianzhongdeMacBook-Pro:chapter_17 shijianzhong$ 
    

    io.sync

    io.sync=(state)

    sync是syncchronize(同步)的意思。设定了这个就不需要io.flush

    第1次: 5
    第2次: 10
    第3次: 15
    结束后: 15
    "aaaaaaaaaaaaaaa"
    shijianongdeMBP:chapter_17 shijianzhong$ cat test_buffering3.rb 
    filename = "buffering.txt"
    File.open(filename, "w") do |file|
      file.sync = true
      3.times do |i|
        # 检查写入5次字节后的文件的大小
          file.write("a" * 5)
          puts "第#{i+1}次: #{File.size(filename)}"
      end
    end
    
    puts "结束后: #{File.size(filename)}"
    p File.read(filename)
    shijianongdeMBP:chapter_17 shijianzhong$ 
    

    与命令进行交互

    IO.popen(command, mode)

    参数 mode的使用方法与File.open方法是一样,参数缺省时默认是"r"模式。

    用IO.popen方法生成的IO对象的输入/输出,会关联启动的命令command的标准输入/标准版输出。也就是说,IO对象的输出会作为命令的输入,命令的输出则会作为IO对象的输入

    shijianongdeMBP:chapter_17 shijianzhong$ cat simple_grep_gz.rb 
    pattern = Regexp.new(ARGV[0])
    filename = ARGV[1]
    if /.gz$/ =~ filename
      file = IO.popen("zcat #{filename}")   # 指定命令输出io流
    else
      file = File.open(filnename)
    end
    
    file.each_line do |line|   # 逐行读取文件
      if pattern =~ line
        print line
      end
    end
    

    open("|command", mode)

    将带有管道符号的命令传给open方法的效果与使用IO.pepon方法一样

    finename = ARGV[0]
    open("|zcat #{filename}") do |io|
      io.each_line do |line|
        print line
      end
    end
    

    open-url库

    通过require引用open-uri库后,我们可以像打开普通文件一样打开HTTP,FTP的URL。

    shijianongdeMBP:chapter_17 shijianzhong$ cat read_url.rb 
    require "open-uri"
    
    open("http://www.ruby-lang.org/zh_cn/") do |io|
      puts io.read   # 输出网页信息
    end
    
    # 通过FTP读取数据
    filename = "ruby-2.3.0.tar.gz"
    url = "ftp://www.ruby-lang.org/pub/ruby/2.3/#{filename}"
    open(url) do |io|
      File.binwrite(filename, io.read)  # 写入文件
    end
    

    stringio库

    StringIO就时用于模拟IO对象的修昂。通过require引用stringio库后,就可以使用stringIO对象了

    "A
    B
    C
    "
    shijianongdeMBP:chapter_17 shijianzhong$ cat stringio_puts.rb 
    require "stringio"
    
    io = StringIO.new
    io.puts("A")
    io.puts("B")
    io.puts("C")
    io.rewind
    p io.read  # 进行输出操作
    

    通过将字符串传递给StringIO.new方法的参数,就可以由字符串创建StringIO对象

    rld writable dir /usr/local/opt/mysql@5.7/bin in PATH, mode 040777
    "A
    "
    "B
    "
    "C
    "
    shijianongdeMBP:chapter_17 shijianzhong$ cat stringio_gets.rb 
    require "stringio"
    
    io = StringIO.new("A
    B
    C
    ")
    p io.gets
    p io.gets
    p io.gets
    

    练习题

     1 创建脚本,统计文本的行数,统计文本的单词数,统计文本的字符数

    shijianzhongdeMacBook-Pro:exercises shijianzhong$ cat e1.rb 
    def count_file(file)
      lines = File.readlines(file).size
      word_size = File.read(file).split.size
      character = File.read(file).size 
      [lines, word_size, character]
    end
    
    p count_file(ARGV[0])
    

    2 创建脚本,将文件中的行逆序排序,保留文件中的第一行数据

  • 相关阅读:
    linux常用的基础知识
    【AW346】走廊泼水节
    【AW355】异象石
    【POJ3417】闇の連鎖
    【APIO2010】巡逻
    【SDOI2011】消防
    【BJWC2010】次小生成树
    【POJ3613】Cow Relays
    【POJ1734】Sightseeing trip
    【POJ1094】Sorting it all out
  • 原文地址:https://www.cnblogs.com/sidianok/p/13069885.html
Copyright © 2020-2023  润新知