IO 1/2

Aula 16

Objetivo

Como fazer IO (Input / Output) básico em Ruby.

Classe IO

File – Abrindo e fechando


file = File.open("arquivo.txt", "r")
#processa arquivo
file.close

File.open("arquivo", "r") do |file|
  #processa arquivo
end

file = open("arquivo", "r")
...

Modos

r Read-only, starts at beginning of file (default mode).
r+ Read/write, starts at beginning of file.
w Write-only, truncates an existing file to zero length or creates a new file for writing.
w+ Read/write, truncates existing file to zero length or creates a new file for reading and writing.
a Write-only, starts at end of file if file exists; otherwise creates a new file for writing.
a+ Read/write, starts at end of file if file exists; otherwise creates a new file for reading and writing.
b (DOS/Windows only) Binary file mode (may appear with any of the key letters listed above).

Lendo e escrevendo

Os métodos puts, putc, gets, getc, printf (presentes em Kernel) são todos métodos da classe IO.



in_f = File.open("entrada.txt", "r")
out = File.open("saida.txt", "w+")

count = 1
while(linha = in_f.gets)
  out.printf "%10d -  %s", count, linha
  count += 1
end

in_f.close; out.close

Alguns métodos de IO

IO#puts, IO#putc, IO#gets, IO#getc, IO#printf, IO#print, IO#write

IO.read(filename) -> string
IO.readlines(filename) -> array

IO#eof?, IO#lineno, IO#pos, IO#pos=, IO#rewind, IO#seek

#seek versus #pos=


file = open('texto.txt', 'r')
file.pos = 10
file.gets # => 
file.seek(10)  # equivalente a file.pos = 10 e file.seek(10, IO::SEEK_SET)
file.gets # => 
file.seek(10, IO:SEET_CUR) # avança 10 da atual
file.gets # => 
file.seek(-10, IO:SEET_END) # 10 antes do fim
file.gets # => 
file.close

Mais exemplos


open("texto.txt", "r+") do |file|
  primeira_linha = file.gets
  primeiro_c_seg_linha = file.getc
  seg_linha = file.gets
  file.seek(-10, IO::SEEK_END)
  array_of_lines = file.readlines
  file.seek(-10, IO::SEEK_END)
  file.puts("substitui últimos 10 chars")
  file.rewind
  char = file.getc
  file.seek(0, IO::SEEK_END)
  file.putc(char)
end

Caracteres (Bytes) em Ruby

São simples inteiros, de 0 a 255. #getc lê um caractere e #putc escreve caractere.


c = $stdin.getc  # aguarda leitura do caractere
$stdout.puts c  #recebe inteiro e imprime o caractere correspondente
"um string"[3]    # => 115  - caractere "s" 

$stdin, $stdout e $stderr

A entrada padrão, saída padrão, e saída de erro padrão são objetos IO. Redirecionando a saída:



def out_to_file(out_f_name)
  terminal= $stdout
  file_out= open(out_f_name, "w+")
  $stdout = file_out
  yield
ensure
  file_out.close
  $stdout = terminal
end

out_to_file("saida.txt") do 
  puts "tudo feito aqui vai para saida.txt"
end
puts "aqui vai para o terminal"

Iteradores dos objetos de IO

IO#each_byte Itera byte a byte (8 bits). Passa char (inteiro de 0 a 255) como parâmetro do bloco.
IO#each_line ou IO#each Itera linha a linha. Passa a linha (String) como parâmetro do bloco.
IO.foreach Abre arquivo e itera linha a linha, de uma vez só.

Iteradores dos objetos de IO


in_f = File.open("entrada.txt", "r")
out = File.open("saida.txt", "w+")
in_f.each_with_index do |line, index|
  out.printf "%10d -  %s", index + 1, line
end
in_f.close; out.close

Iteradores dos objetos de IO


out = File.open("saida.txt", "w+")
count = 1
IO.foreach("entrada.txt") do |line|
  out.printf("%10d -  %s", count, line)
  count += 1
end
out.close

Iteradores dos objetos de IO


in_f = File.open("entrada.txt", "r")
out = File.open("saida.txt", "w+")
in_f.inject(1) do |count, line|
  out.printf("%10d -  %s", count, line)
  count + 1
end
in_f.close; out.close

StringIO

Uma classe que permite usar um objeto de IO que escreve/le em um String. Útil em testes.


require 'stringio'
ip = StringIO.new("now is\nthe time\nto learn\nRuby!")
op = StringIO.new("", "w")
ip.each_line do |line|
  op.puts line.reverse
end
op.string   → "\nsi won\n\nemit eht\n\nnrael ot\n!ybuR\n"

IO para Redes

O protocolo TCP é o mais popular da internet. É o que vai ser utilizado no lab 6.


require 'socket'
client = TCPSocket.open('127.0.0.1', 'finger')
client.send("mysql\n", 0)    # 0 means standard packet
puts client.readlines
client.close

TCPServer

Aceita conexões (permite criação de servidores).


require 'socket'
server = TCPServer.new('localhost', 80)
while (session = server.accept)
  puts "Request: #{session.gets}"
  session.print "HTTP/1.1 200/OK\r\nContent-type: text/html\r\n\r\n"
  session.print "<html><body><h1>#{Time.now}</h1></body></html>\r\n"
  session.close
end

Bibliotecas do módulo Net

Conversam com protocolos na camada de aplicação (nível mais alto que o TCP):

Ex de HTTP


require 'net/http'
h = Net::HTTP.new('www.pragmaticprogrammer.com', 80)
response = h.get('/index.html', nil)
if response.message == "OK"
  puts response.body.scan(/<img src="(.*?)"/m).uniq
end

Open URI

Biblioteca que extende o Kernel#open para para abrir URIs (ou URLs). Segue redirecionamentos e age como um cliente HTTP/FTP completo.


require 'open-uri'
open('http://www.pragmaticprogrammer.com') do |f|
  puts f.read.scan(/<img src="(.*?)"/m).uniq
end

YAML

É um padrão simples “legível por humanos” para serialização de estruturas de dados. Suporta arrays, hashes e OO em geral. Bibliotecas disponíveis nas mais diversas linguagens.


require 'yaml'
tree = { :name => 'ruby',
         :uses => [ 'scripting', 'web', 'testing', 'etc' ]
       }
File.open("tree.yml", "w") {|f| YAML.dump(tree, f)}

YAML


require 'yaml'
tree = YAML.load(File.open("tree.yml"))
tree[:uses][1]   → "web"

to_yaml


class Aluno
  attr_accessor :nome, :professor
end
class Professor
  attr_accessor :nome
end

a = Aluno.new
p = Professor.new
p.nome = "Marcelo"
a.nome = "Joao"
a.professor = p
File.open("aluno.yml", "w") {|f| f.puts(a.to_yaml) }

Serialização – Outras opções

Referências