====== Wejscie i wyjscie ====== ===== Klawiatura ===== * ''gets'' pobiera pojedyncza linie danych ze standardowego wejscia, * ''readlines'' czyta wszystkie linie, dopoki nie napotka terminatora (EOF - End Of File, na przyklad Ctrl+D). Napotkawszy EOF, zwraca linie w tablicy. ===== Pliki ===== File.open("text.txt").each { |line| puts line } File.new("text.txt", "r").each { |line| puts line } Obydwa polecenia otwieraja plik do odczytu (''File.open'' - domyslnie, ''File.new'' poprzez "r"). Ponadto ''File.open'' moze przyjac blok kodu, a gdy dzialanie tego sie zakonczy, zamknie plik, co nie dzieje sie w przypadku drugiej metody (trzeba skorzystac z metody ''close''). File.open("text.txt") do |f| puts f.gets end f = File.new("text.txt", "r") puts f.gets f.close Korzystajac z pierwszej opcji, mamy szybki i prosty sposob na przeprowadzenie operacji w pojedynczej lokalizacji. W drugim przypadku, udostepniamy referencje szerszej "publice". * ''each_byte'' wczytuje strumien bajt po bajcie. Otrzymujemy wtedy pojedyncze wartosci bajtow a nie znaki. Aby przekonwertowac je na znaki, mozna skorzystac z metody ''chr''. * ''each_char'' wczytuje strumien znak po znaku. Jest to przydatne, gdy korzystamy z zestawu znakow, w ktorych niektore znaki przedstawiane sa za pomoca wiecej niz jednego bajta. * ''read(6)'' wczytuje 6 bajtow z pliku. * Klasa ''File'' posiada wiele przydatnych metod do szybkiej obslugi plikow: * ''data = File.read(filename)'' otwiera plik, uzywa metody ''read'' i zamyka go. * ''array_of_lines = File.readlines(filename)''. * ''pos'' pokazuje, w ktorym miejscu w pliku sie znajdujemy. * ''pos='' umieszcza wskaznik w danym miejscu (''f.pos = 8'') # writing.rb File.open("test.txt", "w") do |f| f.puts "This is a test" end Output: sqbell@sqbell-gentoo ~/ruby/beginning_ruby/ch09_files_db $ cat test.txt This is a test ^ Tryby ^ Wlasnosci ^ | ''r'' | Tylko do odczytu, wskaznik na poczatku pliku | | ''r+'' | Odczyt i zapis, wskaznik na poczatku pliku | | ''w'' | Tylko zapis, nowy plik jest tworzony (istniejace sa zastepowane) | | ''w+'' | Zapis i odczyt, ''File.new'' tworzy nowy plik (istniejacy jest zastepowany) | | ''a'' | Zapis w trybie dolaczania do pliku, wskaznik jest umieszczony na koncu pliku | | ''a+'' | Zapis i odczyt w trybie dolaczania, wskaznik umieszczony jest na koncu pliku | | ''b'' | Tryb binarny, do odczytu plikow nietekstowych | # logging.rb f = File.new("logfile", "a") f.puts Time.now f.close Output: sqbell@sqbell-gentoo ~/ruby/beginning_ruby/ch09_files_db $ cat logfile 2011-05-06 13:10:29 +0200 2011-05-06 13:10:30 +0200 2011-05-06 13:10:31 +0200 2011-05-06 13:10:32 +0200 * ''File.rename("file1", "file2")'' zmienia nazwe pliku. * ''File.delete("file")'' lub ''File.unlink("file")'' usuwa plik. * ''File.join('full', 'path', 'to', 'a', 'file.txt')'' generuje sciezke dostepu. * ''File.expand_path("file")'' wyswietli absolutna sciezke do pliku. * ''puts "It exists!" if File.exist?("file")'' sprawdzi czy plik istnieje. * ''puts File.size("file")'' wyswietli rozmiar pliku. ==== Blokady ==== W systemach UNIXowych mamy dwa rodzaje blokad: współdzielona (//shared//) i na wyłączność ((//exclusive//). Druga może być w posiadaniu tylko przez jeden proces. Procesy współdzielące plik muszą najpierw zwlonić blokadę, by proces, który chce posiadać plik na wyłączność będzie mógł taką założyć. Przykład w Rubym: #!/usr/bin/env ruby -wKU File.open("/tmp/foo", "w") do |f| f.flock(File::LOCK_EX) f.puts "Something clever..." f.flock(File::LOCK_UN) end ==== Katalogi ==== * ''Dir.chdir("/usr/bin")'' zmienia katalog, * ''Dir.pwd'' wyswietla obecny katalog, * ''Dir.entries("/usr/bin")'' zwroci tablice zawartosci katalogu, * ''Dir.foreach("/usr/bin")'' dziala podobnie, ale jest iteratorem, * ''Dir["/usr/bin/*"]'' wyswietli liste podkatalogow, * ''%%Dir["**/**"]%%'' wyświetli wszystkie pliki i katalogi w obecnym katalogu, rekursywnie, * ''Dir.mkdir("newdir")'' tworzy katalog, * ''Dir.delete("newdir")'' usuwa katalog, podobnie jak ''Dir.unlink'' i ''Dir.rmdir''. === Tworzenie plikow tymczasowych === Wiekszosc systemow operacyjnych posiada katalogi, w ktorych programy moga przechowywac tymczasowe dane. # tmp_dir.rb require 'tmpdir' puts Dir.tmpdir tempfilename = File.join(Dir.tmpdir, "myapp.dat") tempfile = File.new(tempfilename, "w") tempfile.puts "This is only temporary." tempfile.close File.delete(tempfilename) # poprzez biblioteke tempfile require 'tempfile' f = Tempfile.new('myapp') f.puts "Hello" puts f.path f.close Output: /tmp /tmp/myapp20110506-5927-3wba79 ==== Strony kodowe ==== Aby okreslic kodowanie wczytywanego pliku, dodajemy je do trybu pliku po dwukropku. File.new("text.txt", "r:utf-8").each { |line| puts line } Aby sprawdzic "zewnetrzne" kodowanie jakiegokolwiek obiektu I/O, skorzystac mozemy z metody ''external_encoding''. # ext_encoding.rb puts File.open("logfile", "r:utf-8").external_encoding puts File.open("logfile", "r").external_encoding Output: UTF-8 UTF-8 Mozna transkodowac wejscie z jednego kodowania w drugie: # transcoding.rb File.open("text.txt", "r:utf-8:iso-8859-2") do |f| puts f.external_encoding first_line = f.gets puts first_line.encoding end Output: UTF-8 ISO-8859-2 Wlasnosc ta jest przydatna gdy chcemy w calym programie korzystac z jednego kodowania (na przyklad utf-8) ale pliki wejsciowe mamy w innym. ====== Podstawowe bazy danych ====== ===== Bazy danych w plikach tekstowych ====== ==== CSV ==== # csv.rb require 'csv' CSV.open('text.txt', 'r').each do |person| puts person.inspect end Output: ["Fred Bloggs", "Manager", "Male", "45"] ["Laura Smith", "Cook", "Female", "23"] ["Debbie Watts", "Professor", "Female", "38"] ===== Przechowywanie obiektow i struktur danych ===== ==== PStore ==== PStore umozliwia zapisywanie obiektow i struktur danych do pliku i ladowania ich z powrotem. Takie operacje zwane sa //object persistence// i opieraja sie na technice zwanej //marshalling//, gdzie struktury sa splaszczane. # pstore.rb class Person attr_accessor :name, :job, :gender, :age end fred = Person.new fred.name = "Fred Bloggs" fred.age = 45 laura = Person.new laura.name = "Laura Palmer" laura.age = 23 require 'pstore' store = PStore.new("storagefile") store.transaction do store[:people] ||= Array.new store[:people] << fred store[:people] << laura end * Wszelkie operacje wykonujemy w "transakcji", by zapobiec uszkodzeniu danych. * Poprzez ''||='' upewniamy sie, ze element '':people'' znajduje sie w danej 'przechowalni'. Nastepnie dodajemy do niego freda i laure (''<<'') i konczymy transakcje. # pstore_read.rb class Person attr_accessor :name, :job, :gender, :age end require 'pstore' store = PStore.new("storagefile") people = [] store.transaction do people = store[:people] end people.each do |person| puts person.name end Output: Fred Bloggs Laura Palmer ==== YAML ==== # yaml.rb require 'yaml' class Person attr_accessor :name, :age end fred = Person.new fred.name = "Fred Bloggs" fred.age = 45 laura = Person.new laura.name = "Laura Smith" laura.age = 23 test_data = [ fred, laura ] puts YAML::dump(test_data) Output: --- - !ruby/object:Person age: 45 name: Fred Bloggs - !ruby/object:Person age: 23 name: Laura Smith Wczytywanie: # yaml_read.rb require 'yaml' class Person attr_accessor :name, :age end yaml_string = < Output: Fred Bloggs Laura Smith ===== Relacyjne bazy danych i SQL ===== ==== SQLite ==== # sqlite.rb require 'rubygems' require 'sqlite3' $db = SQLite3::Database.new("dbfile") # $ - zmienna globalna $db.results_as_hash = true # wymusza zwracanie wynikow jako hasha def disconnect_and_quit $db.close puts "Bye!" exit end def create_table puts "Creating 'people' table" $db.execute %q{CREATE TABLE people ( id integer primary key, name varchar(50), job varchar(50), gender varchar(6), age integer) } end def add_person puts "Enter name: " name = gets.chomp puts "Enter job: " job = gets.chomp puts "Enter gender: " gender = gets.chomp puts "Enter age: " age = gets.chomp $db.execute("INSERT INTO people (name, job, gender, age) VALUES (?, ?, ?, ?)", name, job, gender, age) end def find_person puts "Enter name or ID of person to find: " id = gets.chomp person = $db.execute("SELECT * FROM people WHERE name = ? OR id = ?", id, id.to_i).first unless person puts "No result found." return end puts %Q{Name: #{person['name']} Job: #{person['job']} Gender: #{person['gender']} Age: #{person['age']} } end ==== MySQL ==== # mysql.rb require 'rubygems' require 'mysql' db = Mysql.connect('localhost', 'root', 'test') db.query("INSERT INTO people (name, age) VALUES('Chris', 25)") begin query = db.query('SELECT * FROM people') puts "There were #{query.num_rows} rows returned." query.each_hash do |h| puts h.inspect end rescue puts db.errno puts db.error end db.close ==== DBI ==== DBI (The DataBase Interface) to proba utworzenia jednego interfejsu do porozumiewania sie z roznymi bazami danych. # dbi.rb require 'dbi' db = DBI.connect('DBI:Mysql:db_name', 'username', 'password') db.do("INSERT INTO people (name, age) VALUES (?, ?)", name, age) query = db.prepare('SELECT * FROM people') query.execute while row = query.fetch do puts row.inspect end query.finish db.select_all('SELECT * FROM people') do |row| puts row.inspect end