zoukankan      html  css  js  c++  java
  • 《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 创建脚本,将文件中的行逆序排序,保留文件中的第一行数据

  • 相关阅读:
    每日一篇文献:Robotic pick-and-place of novel objects in clutter with multi-affordance grasping and cross-domain image matching
    每日一篇文献:Intuitive Bare-Hand Teleoperation of a Robotic Manipulator Using Virtual Reality and Leap Motion
    每日一篇文献:Virtual Kinesthetic Teaching for Bimanual Telemanipulation
    HEBI Robotic Arm VR Teleoperation
    「iQuotient Case」AR device teleoperated robotic arm
    VR and Digital Twin Based Teleoperation of Robotic Arm
    HEBI Robotic Arm VR Teleoperation
    Human Robot Interaction
    Immersive Teleoperation Project
    机器人演示学习
  • 原文地址:https://www.cnblogs.com/sidianok/p/13069885.html
Copyright © 2011-2022 走看看