Operacje wejścia-wyjścia w Rubim
Posted by Jacek Galanciak on Jul 4 2007
W tej części tutoriala nauczymy się korzystać z wejścia i wyjścia na poziomie daleko wykraczającym poza programy “Hello World!”…
Kernel
Moduł Kernel
dostarcza nam podstawowe metody związane z obsługą wejścia i wyjścia. Oto i one:
putc
- wyświetla znak o kodzie ASCII podanym za argument; zwrócmy uwagę, że dodanie do kodu wielokrotności liczby 256 wyświetli taki sam znak
(97..99).each do |c|
putc c
end
(354..356).each do |c|
putc c
end
Co na wyjściu da nam:
abcbcd
puts
- wyświetla tekst podany za argument, dodając na koniec znak końca linii; jeśli argumentem jest tablica, wyświetla każdy element, oddzielając je separatorem linii; jeżeli którykolwiek z elementów zawiera już separatory, metoda usuwa jeden z nich
puts "Hello World!"
puts ["To\n", "tylko\n\n", "test"];
Wyjście:
Hello World!
To
tylko
test
print
- wypisuje obiekt (lub obiekty) na standardowe wyjście; odziela każdy z nich łańcuchem określonym w zmiennej magicznej $,
(która domyślnie ma wartość nil
); dodaje na koniec Stringa wynikowego zawartość $\
(domyślnie nil
)
print "a", 1, [2, '4'], "b", "\n"
$, = ", "
$\ = "\n"
print "a", 1, [2, '4'], "b"
Wyjście:
a124b
a, 1, 2, 4, b
Zwróćmy uwagę, że po ustawieniu zmiennej $\
nie musimy dorzucać znaku \n
na koniec sekwencji obiektów.
printf
- działa tak samo, jak standardowa funkcja języka C o takiej samej nazwie
open
- otwiera plik (jeśli parametr nie rozpoczyna się znakiem |
) lub potok podprocesu.
Poniższy program na dwa sposoby realizuje odczyt pierwszej linii pliku:
# 1
f = open "C:\\plik.txt"
puts f.gets
# 2
open "C:\\plik.txt" do |f|
puts f.gets
end
Rozpoczynając parametr metody open
znakiem potoku, otwieramy podproces z możliwością śledzenia jego wyjścia oraz zapisu danych na jego wejście. Napiszemy teraz program, który wywołuje systemowe polecenie ls
(lub jakiekolwiek inne) i wyświetli wynik jego działania na ekranie.
open("|ls") do |f|
while ln = f.gets do puts ln end
end
Wyniku działania, ze względów bezpieczeństwa, nie podam :-).
Operujemy na plikach
Można to robić w sposób klasyczny lub blokowy:
# 1
f = File.open "C:\\plik.txt"
while ln = f.gets do puts ln end
f.close
# 2
File.open "C:\\plik.txt" do |f|
while ln = f.gets do puts ln end
end
Przewaga tego drugiego jest dokładnie widoczna, gdy zwracany jest wyjątek. Pierwszy sposób może wtedy ominąć metodę zamykającą plik. Stosując podejście blokowe, możemy kodować (i spać) spokojnie.
Zapis do pliku realizujemy za pomocą metod puts
, print
itp. obiektu klasy File
, które działają tak samo, jak ich imiennicy z modułu Kernel
.
Używamy iteratorów
Iteratory to potężne narzędzie (pisałem o nich w poprzedniej części tutoriala), zaimplementowano takowe również do operacji wejścia i wyjścia.
Stwórzmy przykładowy plik o następującej zawartości:
Pierwsza linia
Druga linia
A to jest trzecia
Napiszemy teraz program, który, z wykorzystaniem iteratorów, odczyta kolejno wszystkie znaki (oddzielając każdy minusem) i każdą linię pliku, informując o odczytanym wierszu.
File.open "C:\\plik.txt" do |f|
f.each_byte { |c| putc c; print "-" }
end
puts # Przejście do nowego wiersza
File.open "C:\\plik.txt" do |f|
f.each_line { |ln| puts "Napotkałem na wiersz: #{ln}" }
end
Output:
P-i-e-r-w-s-z-a- -l-i-n-i-a--
-D-r-u-g-a- -l-i-n-i-a--
-A- -t-o- -j-e-s-t- -t-r-z-e-c-i-a-
Napotkałem na wiersz: Pierwsza linia
Napotkałem na wiersz: Druga linia
Napotkałem na wiersz: A to jest trzecia
Nic nie stoi na przeszkodzie, byśmy sami wybrali sobie separator linii, gdy domyślny (\n
) nam nie odpowiada.
File.open "C:\\plik.txt" do |f|
f.each_line(" ") { |ln| puts ln }
end
Pierwsza
linia
Druga
linia
A
to
jest
trzecia
Jak widać w tym przypadku, za separator linii obraliśmy sobie spację.
Aby URL plikiem się stał
To żaden problem. Wystarczy dodać jedną linię kodu, aby można było traktować adresy internetowe jak zwykłe pliki. Poniższy program wyświetli kod HTML wyszukiwarki Google.
require 'open-uri'
open("http://google.com") do |f|
puts f.readlines
end
Prawda, że piękne?