Programmierung in Ruby

Der Leitfaden der Pragmatischen Programmierer

class IO
Parent: Object
Version: 1.6

Index:

foreach new pipe popen readlines select << binmode clone close close_read close_write closed? each each_byte each_line eof eof? fcntl fileno flush getc gets ioctl isatty lineno lineno= pid pos pos= print printf putc puts read readchar readline readlines reopen rewind seek stat sync sync= sysread syswrite tell to_i to_io tty? ungetc write



Subclasses: File

Die Klasse IO ist die Basis aller Ein- und Ausgabevorgänge in Ruby. Ein I/O-Stream kann ge-duplexed, d.h. bidirektional, sein und kann somit mehr als einen nativen Stream des Betriebssystems nutzen.

Viele Beispiel in diesem Abschnitt benutzen die Klasse File, die die einzige Standard-Subklasse von IO ist. Beide Klassen sind eng miteinander verknüpft.

Die in diesem Abschnitt benutzte Variable einPortname kann jede der folgenden Formen haben.

Ruby konvertiert---soweit möglich---Pfadangaben zwischen verschiedenen Betriebssystemkonventionen. Zum Beispiel wird der Dateiname ``/gumby/ruby/test.rb'' unter Windows als ``\gumby\ruby\test.rb'' geöffnet. Beachte: Wenn Windows-konforme Dateinamen in einem Ruby-String gespeichert werden, müssen die Backslashes mit der Escape-Sequenz versehen werden, da sie spezielle Zeichen sind.

"c:\\gumby\\ruby\\test.rb"

In unsere Beispiele werden Unix-konforme vorgeneigte Schrägstriche (forward slash) benutzt; File::SEPARATOR kann verwendet werden, um den Plattformspezifischen Separator zu erhalten.

I/O Ports können in einem von mehreren Moden geöffnet werden, die in diesem Abschnitt als einModusString wiedergegeben sind. Diese Modus Strings müssen einem der Werte aus der folgenden Tabelle 22.5 entsprechen.

Modus Strings
Modus Bedeutung
``r'' Nur-Lesen, beginnt am Anfang der Datei (Standardmodus).
``r+'' Lesen-Schreiben, beginnt am Anfang der Datei.
``w'' Nur-Schreiben, schneidet exisiterende Dateien auf Null-Länge ab bzw. eröffnet eine neue Datei für den Schreibzugriff.
``w+'' Lesen-Schreiben, schneidet bestehende Dateien auf Null-Länge ab bzw. öffnet eine neue Datei für den Lese- und Schreibzugriff.
``a'' Nur-Schreiben, beginnt am Ende der Datei, wenn die Datei exisitiert. Sonst wird eine neue Datei für den Schreibzugriff geöffnet.
``a+'' Lesen-Schreiben, beginnt am Ende der Datei, falls die Datei existiert. Anderenfalls wird eine neue Datei für den Schreib- und Lesezugriff geöffnet.
``b'' (nur DOS/Windows) Binärdateimodus (kann mit jedem der oben genannten Modi kombiniert werden).

mixins
Enumerable: collect, detect, each_with_index, entries, find, find_all, grep, include?, map, max, member?, min, reject, select, sort, to_a

class methods
foreach IO.foreach( einPortName, einSepString=$/ ) {| line | block }-> nil

Führt den Code-Block für jede Zeile im angegebenen I/O-Port aus. Dabei stellt einSepString den Zeilentrenner dar.

IO.foreach("testfile") {|x| print "GOT ", x }
ergibt:
GOT This is line one
GOT This is line two
GOT This is line three
GOT And so on...

new IO.new( einInteger, einModusString ) -> eineDatei

Gibt ein neues File-Objekt (einen Stream) für den angegebenen ganzzahligen Datei-Deskriptor und ModusString zurück. Siehe auch IO#fileno.

a = IO.new(2,"w")      # '2' is standard error
$stderr.puts "Hello"
a.puts "World"
ergibt:
Hello
World

pipe IO.pipe -> einArray

Erzeugt ein Paar von (miteinander verbundenen) Pipe-Endpunkten und gibt sie als Array mit zwei Elementen von IO-Objekten zurück: [leseDatei, schreibDatei]. Die Methode ist nicht auf allen Plattformen verfügbar.

Im unten gezeigten Beispiel schließen die beiden Prozesse jeweils die Enden der Pipe, die sie nicht benutzen. Dies ist nicht nur eine kosmetische Schönheitsoperation: Das Lese-Ende der Pipe generiert keine EOF-Bedingung, so lange noch offene Schreibzugriffe auf der Pipe liegen. Im Falle des Eltern-Prozesses, wird rd.read nie enden, wenn nicht zuvor ein wr.close erfolgt ist.

rd, wr = IO.pipe

if fork   wr.close   puts "Parent got: <#{rd.read}>"   rd.close   Process.wait else   rd.close   puts "Sending message to parent"   wr.write "Hi Dad"   wr.close end
ergibt:
Sending message to parent
Parent got: <Hi Dad>

popen IO.popen( einCmdString, einModusString="r" ) -> einIO
IO.popen( einCmdString, einModusString="r" ) {| anIO | block }-> nil

Führt den angegebenen Kommando-String als einen Unterprozess aus. Die Standardeingabe und -ausgabe wird mit dem zurückgegebenen IO-Objekt verknüpft. Wenn einCmdString mit ``-'' beginnt, wird eine neue Instanz von Ruby als Unterprozess gestartet. Der Standard-Modus für das neue Dateiobjekt ist ``r'', aber einModusString kann jeden in der Tabelle 22.5 aufgeführten Wert enthalten.

Wenn ein Code-Block angegeben ist, führt Ruby das Kommando als einen Kindprozess aus, der mit Ruby durch einen Pipe verbunden ist. Ruby's Seite der Pipe wird als parameter an den Code-Block weitergegeben.

Wenn ein Code-Block mit einCmdString von ``-'' gegeben ist, wird der Code-Block in zwei separaten Prozessen ausgeführt: Einmal im Elternprozess und einmal im Kindprozess. Der Elternprozess erhält das Pipe-Objekt als Parameter für dne Code-Block, während der Code-Block im Kindprozess nil erhält. Die Standardeingabe und -ausgabe des Kindprozesses wird mit dem Elternprozess durch eine Pipe verküpft. Dies ist nicht auf allen Plattformen verfügbar.

f = IO.popen("uname")
p f.readlines
puts "Parent is #{Process.pid}"
IO.popen ("date") { |f| puts f.gets }
IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f}"}
ergibt:
["Linux\n"]
Parent is 15506
Sun Mar  4 23:28:51 CST 2001
15509 is here, f is
15506 is here, f is #<IO:0x4018d518>

readlines IO.readlines( einPortName, einSepString=$/ ) -> einArray

Liest die gesamte durch einPortName bezeichnete Datei zeilenweise ein und gibt diese Zeilen als Array zurück. einSepString wird als Zeilentrenner verwendet.

a = IO.readlines("testfile")
a[0] » "This is line one\n"

select IO.select( readArray[, writeArray[errorArray[timeout]]] ) -> einArray
oder nil

Siehe Kernel#select weiter unten.

instance methods
<< ios << einObject-> ios

String Ausgabe---Schreibt einObject nach ios. einObject wird mit to_s in einen String konvertiert.

$stdout << "Hello " << "world!\n"
ergibt:
Hello world!

binmode ios.binmode -> ios

Setzt ios in den Binärmodus. Dies ist nur in MS-DOS/Windows Umgebungen sinnvoll. Wenn ein Stream in den Binärmodus gesetzt wurde, kann er nicht mehr in den nicht-binären Modus zurückgesetzt werden.

clone ios.clone -> einIO

Eröffnet einen neuen I/O-Stream und kopiert dabei alle Attribute von ios. Auch die Dateiposition wird geteilt, so dass ein Lesevorgang auf dem Clone auch die Position des Originals verschiebt (und umgekehrt).

close ios.close -> nil

Schließt ios und gibt alle wartenden Schreibzugriffe an das Dateisystem weiter. Der Stream ist danach für alle weiteren Datenoperationen nicht mehr verfügbar; ein Versuch, dies trotzdem zu tun, führt zu einem IOError. I/O-Streams werden automatisch geschlossen, wenn sie vom Garbage Collector beansprucht werden.

close_read ios.close_read -> nil

Schließt das Lese-Ende eines duplex-I/O-Streams (d.h., eines Streams, der sowohl einen Lese- als auch einen Schreib-Stream besitzt, wie z.B. eine Pipe). Wenn der Stream keine Duplex-Eigenschaft hat, wird ein IOError geworfen.

f = IO.popen("/bin/sh","r+")
f.close_read
f.readlines
ergibt:
prog.rb:3:in `readlines': not opened for reading (IOError)
	from prog.rb:3

close_write ios.close_write -> nil

Schließt das Schreib-Ende eines duplex-I/O-Streams (d.h., eines Streams, der sowohl einen Lese- als auch einen Schreib-Stream besitzt, wie z.B. eine Pipe). Wenn der Stream keine Duplex-Eigenschaft hat, wird ein IOError geworfen.

f = IO.popen("/bin/sh","r+")
f.close_write
f.print "nowhere"
ergibt:
prog.rb:3:in `write': not opened for writing (IOError)
	from prog.rb:3:in `print'
	from prog.rb:3

closed? ios.closed? -> true oder false

Gibt true zurück, wenn ios vollständig geschlossen ist (für duplex-Streams, also sowohl Lese- wie auch Schreibstream), sonst false.

f = File.new("testfile")
f.close » nil
f.closed? » true
f = IO.popen("/bin/sh","r+")
f.close_write » nil
f.closed? » false
f.close_read » nil
f.closed? » true

each ios.each( einSepString=$/ ) {| line | block }-> ios

Führt den Codeblock für jede Zeile in ios aus, wobei aSepString als Zeilentrenner verwendet wird. ios muss für den Lesezugriff geöffnet sein, sonst wird ein IOerror geworfen.

f = File.new("testfile")
f.each {|line| puts "#{f.lineno}: #{line}" }
ergibt:
1: This is line one
2: This is line two
3: This is line three
4: And so on...

each_byte ios.each_byte {| byte | block }

-> nil

Ruft den gegebenen Codeblock einmal für jedes Byte (0..255) in ios aus, wobei das Byte als Argument übergeben wird. Der Stream muss für den Lesezugriff geöffnet sein, sonst wird ein IOerror geworfen.

f = File.new("testfile")
checksum = 0
f.each_byte {|x| checksum ^= x } » nil
checksum » 12

each_line ios.each_line( einSepString=$/ ) {| line | block }

-> ios

Synonym für IO#each.

eof ios.eof -> true oder false

Gibt true zurück, wenn ios am Ende der Datei (end of file, d.Red.) steht. Der Stream muss für den Lese-Zugriff geöffnet sein, sonst wird ein IOError geworfen.

f = File.new("testfile")
dummy = f.readlines
f.eof » true

eof? ios.eof? -> true oder false

Synonym für IO#eof.

fcntl ios.fcntl( einIntegerCmd, einArg ) -> einInteger

Ermöglicht die Ausführung von Kommandos zur Kontrolle oder Abfrage von Datei-orientierten I/O-Streams auf niedriger Systemebene. Argumente und Ergebnis sind Plattform-abhängig. Wenn einArg eine Zahl darstellt, wird sein Wert direkt weitergegeben, während ein String als Binärsequenz von Bytes interpretiert wird. Unter Unix, siehe fcntl(2) für Details. Nicht auf allen Plattformen implementiert.

fileno ios.fileno -> eineFixnum

Gibt den numerischen Deskriptor für ios als Ganzzahl zurück.

$stdin.fileno » 0
$stdout.fileno » 1

flush ios.flush -> ios

Gibt alle gepufferten Daten in ios an das zugrunde liegende Dateisystem weiter (nota bene: Dies betrifft die internen Puffer von Ruby; auch das Betreibssystem kann die Daten puffern).

$stdout.print "no newline"
$stdout.flush
ergibt:
no newline

getc ios.getc -> eineFixnum oder nil

Liest das nächste 8-bit Byte (0..255) aus ios. Die Methode gibt nil zurück, wenn sie am Ende der Datei aufgerufen wird.

f = File.new("testfile")
f.getc » 84
f.getc » 104

gets ios.gets( einSepString=$/ ) -> einString oder nil

Liest die nächste ``Zeile'' vom I/O-Stream, wobei einSepString als Zeilentrenner verwendet wird. Ein Separator vom Wert nil liest den gesamten Inhalt, während ein Separator der Länge Null die Eingabe bis zum Ende des Absatzes liest (ein Absatz ist durch zwei aufeinander folgende Zeilenumbrüche gekennzeichnet). Der Stream muss für den Lesezugriff geöffnet sein, sonst wird ein IOerror geworfen. Die eingelesene Zeile wird zurckgegeben und auch der Variable $_ zugewiesen. Die Methode gibt nil zurück, wenn sie am Ende der Datei aufgerufen wird.

File.new("testfile").gets » "This is line one\n"
$_ » "This is line one\n"

ioctl ios.ioctl( einIntegerCmd, einArg ) -> einInteger

Ermöglicht die Ausführung von Kommandos zur Kontrolle oder Abfrage von I/O-Geräten auf niedriger Systemebene. Argumente und Ergebnis sind Plattform-abhängig. Wenn einArg eine Zahl darstellt, wird sein Wert direkt weitergegeben, während ein String als Binärsequenz von Bytes interpretiert wird. Unter Unix, siehe ioctl(2) für Details. Die Methode ist nicht auf allen Plattformen implementiert.

isatty ios.isatty -> true oder false
Gibt true zurück, wenn ios mit einem Terminal-Endgerät (tty) assoziiert ist, sonst false.

File.new("testfile").isatty » false
File.new("/dev/tty").isatty » true

lineno ios.lineno -> einInteger

Gibt die aktuelle Zeilennummer in ios zurück. Der Stream muss für den Lesezugriff geöffnet sein. lineno zählt, wie oft gets aufgerufen wurde, nicht die Anzahl der gefunden Zeilenumbrüche. Die beiden Werte weichen voneinander ab, wenn gets mit einem Separator aufgerufen wird, der nicht der Zeilenumbruch ist. Vgl. auch die Variable $..

f = File.new("testfile")
f.lineno » 0
f.gets » "This is line one\n"
f.lineno » 1
f.gets » "This is line two\n"
f.lineno » 2

lineno= ios.lineno = einInteger-> einInteger

Setzt die aktuelle Zeilennummer manuell auf den angegeben Wert. Die Variable $. wird erst beim nächsten Lesezugriff aktualisiert.

f = File.new("testfile")
f.gets » "This is line one\n"
$. » 1
f.lineno = 1000
f.lineno » 1000
$. # lineno of last read » 1
f.gets » "This is line two\n"
$. # lineno of last read » 1001

pid ios.pid -> eineFixnum

Gibt die Prozess-ID eines Kind-Prozesses zurück, der mit ios assoziiert ist. Dies kann mit IO.popen gesetzt werden.

pipe = IO.popen("-")
if pipe
  $stderr.puts "In parent, child pid is #{pipe.pid}"
else
  $stderr.puts "In child, pid is #{$$}"
end
ergibt:
In parent, child pid is 15545
In child, pid is 15545

pos ios.pos -> einInteger

Gibt die aktuelle Position (offset vom Dateibeginn) von ios in Bytes zurück.

f = File.new("testfile")
f.pos » 0
f.gets » "This is line one\n"
f.pos » 17

pos= ios.pos = einInteger-> 0

Verschiebt den Zähler in ios auf die angegebene Position (in Bytes).

f = File.new("testfile")
f.pos = 17
f.gets » "This is line two\n"

print ios.print( [einObject=$_]* ) -> nil

Schreibt das (die) angebenen Objekt(e) nach ios. Der Stream muss für den Schreibzugriff geöffnet sein. Wenn der Datenausgabe-Separator ($\) nicht nil ist, wird er an die Ausgabe gehängt. Wenn keine Argumente übergeben werden, wird der Inhalt von $_ ausgegeben. Objekte, die nicht Strings sind, werden mit ihrer to_s-Methode konvertiert. Gibt nil zurück.

$stdout.print("This is ", 100, " percent.\n")
ergibt:
This is 100 percent.

printf ios.printf( einFormatString[, einObject]* ) -> nil

Schreibt eine formatierte Ausgabe nach ios, wobei die Parameterausgabe durch den Formatstring kontrolliert wird. Siehe Kernel#sprintf für details.

putc ios.putc( anObject ) -> anObject

Schreibt das angegebene Zeichen (aus einem String oder einer Fixnum) nach ios.

$stdout.putc "A"
$stdout.putc 65
ergibt:
AA

puts ios.puts( [einObject]* ) -> nil

Schreibt die übergebenen Objekte nach ios analog zu IO#print. Nach jedem Objekt, das nicht mit einem Zeilenumbruch endet schreibt die Methode einen Zeilentrenner (typischerweise ein Zeilenumbruch). Wenn die Methode mit einem Array als Argument aufgerufen wird, schreibt sie jedes Element in eine neue Zeile. Bei Aufruf ohne ein Argument, wird nur ein Zeilenumbruch geschrieben.

$stdout.puts("this", "is", "a", "test")
ergibt:
this
is
a
test

read ios.read( [einInteger] ) -> einString oder nil

Liest höchstens einInteger Bytes vom I/O-Stream ein. Falls anInteger nicht angegeben ist, wird bis zum Ende der Datei gelesen. Gibt nil zurück, wenn der Aufruf am Ende der Datei erfolgt.

f = File.new("testfile")
f.read(16) » "This is line one"

readchar ios.readchar -> eineFixnum

Liest ein Zeichen analog zu IO#getc, wirft jedoch einen EOFError, wenn das Ende der Datei erreicht ist.

readline ios.readline( einSepString=$/ ) -> einString

Liets ein Zeile analog zu IO#gets, wirft jedoch einen EOFError, wenn das Ende der Datei erreicht ist.

readlines ios.readlines( einSepString=$/ ) -> einArray

Liest all Zeilen von ios und gibt sie in einArray zurück. Als Zeilentrenner wird der optionale einSepString verwendet. Der Stream muss für den Lesezugriff geöffnet sein, sonst wird ein IOerror geworfen.

f = File.new("testfile")
f.readlines[0] » "This is line one\n"

reopen ios.reopen( einAndererIO ) -> ios
ios.reopen( einPfad, einModusStr ) -> ios

Assoziiert ios wieder mit dem I/O-Stream, der in einAndererIO gegeben ist bzw. mit einem neuen Stream auf einPfad. Dies kann einen dynamischen Wechsel der Klasse dieses Streams zur Folge haben.

f1 = File.new("testfile")
f2 = File.new("testfile")
f2.readlines[0] » "This is line one\n"
f2.reopen(f1) » #<File:0x4018d608>
f2.readlines[0] » "This is line one\n"

rewind ios.rewind -> 0

Positioniert ios an den Anfang der Eingabe; setzt gleichzeitig lineno auf Null zurück.

f = File.new("testfile")
f.readline » "This is line one\n"
f.rewind » 0
f.lineno » 0
f.readline » "This is line one\n"

seek ios.seek( einInteger, whence=SEEK_SET ) -> 0

Sucht im Stream bis zum angegebenen Offset von einInteger in Übereinstimmung mit dem Wert von whence:

IO::SEEK_CUR Sucht bis einInteger plus aktueller Position.
IO::SEEK_END Sucht bis einInteger plus Ende des Stream (Sie werden wahrscheinlich einen negativen Wert für einInteger) wählen.
IO::SEEK_SET Sucht die absolute Position, die durch einInteger spezifiziert ist.

f = File.new("testfile")
f.seek(-13, IO::SEEK_END) » 0
f.readline » "And so on...\n"

stat ios.stat -> einStat

Gibt die Statusinformation für ios als ein Objekt des Typs File::Stat zurück.

f = File.new("testfile")
s = f.stat
"%o" % s.mode » "100644"
s.blksize » 4096
s.atime » Sun Mar 04 23:28:52 CST 2001

sync ios.sync -> true oder false

Gibt den aktuellen ``sync mode'' von ios zurück. Wenn der sync Modus auf true gesetzt ist, werden alle Ausgaben direkt an das zugrunde liegende Betriebssystem weitergegeben; d.h. sie werden nicht intern durch Ruby gepuffert.

f = File.new("testfile")
f.sync » false

sync= ios.sync = einBoolean-> einBoolean

Setzt den ``sync mode'' auf true oder false. Wenn der sync Modus auf true gesetzt ist, werden alle Ausgaben direkt an das zugrunde liegende Betriebssystem weitergegeben; d.h. sie werden nicht intern durch Ruby gepuffert.

f = File.new("testfile")
f.sync = true

sysread ios.sysread( einInteger ) -> einString
Liest einInteger Bytes unter Verwendung eines Read-Befehls auf niedriger Ebene von ios aus und gibt sie als String zurück. Diese Methode darf nicht zusammen mit anderen Lese-Methoden verwendet werden ios, da sonst unvorhersehrbare Ergebnisse erzielt werden. Die Methode wirft einen SystemCallError bei auftretenden Fehler bzw. einen EOFError, wenn sie am Ende der Datei aufgerufen wurde.

f = File.new("testfile")
f.sysread(16) » "This is line one"

syswrite ios.syswrite( einString ) -> einInteger

Schreibt den übergebenen String mit Hilfe eines Write-Befehls auf niedrigerer Ebene nach ios. Gibt die Anzahl der geschriebenen Bytes zurück. Die Methode sollte nicht zusammen mit anderen Schreibzugriffen auf ios vewendet werden, sonst treten unvorhersehbare Ergebnisse auf. Die Methode wirft bei Fehlern einen SystemCallError.

f = File.new("out", "w")
f.syswrite("ABCDEF") » 6

tell ios.tell -> einInteger

Synonym für IO#pos.

to_i ios.to_i -> einInteger

Synonym für IO#fileno.

to_io ios.to_io -> ios

Gibt ios zurück.

tty? ios.tty? -> true oder false

Synonym für IO#isatty.

ungetc ios.ungetc( einInteger ) -> nil

Schiebt das letzte gelesene Zeichen nach ios zurück, so dass ein darauf folgender Lesezugriff dieses Zeichen wieder einliest. Es kann nur ein Zeichen vor einem neuerlichen Lesezugriff zurückgeschoben werden (d.h., von mehreren zurückgeschobenen Zeichen kann nur das letzte gelesen werden). Die Methode hat keinen Einfluss auf ungepufferte Lesezugriffe (wie IO#sysread).

f = File.new("testfile") » #<File:0x4018d66c>
c = f.getc » 84
f.ungetc(c) » nil
f.getc » 84

write ios.write( einString ) -> einInteger

Schreibt einen gegebenen String nach ios. Der Stream muss für Schreibzugriffe geöffnet sein. Wenn das Argument kein String ist, wird es in einen solchen mit Hilfe der Methode to_s konvertiert. Gibt die Anzahl der geschriebenen Bytes zurück.

count = $stdout.write( "This is a test\n" )
puts "That was #{count} bytes of data"
ergibt:
This is a test
That was 15 bytes of data


Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide"
Übersetzung: Carsten Schinzer
Für das englische Original:
© 2000 Addison Wesley Longman, Inc. Released under the terms of the Open Publication License V1.0. That reference is available for download.
Diese Lizenz sowie das Original vom Herbst 2001 bilden die Grundlage der Übersetzung
Es wird darauf hingewiesen, dass sich die Lizenz des englischen Originals inzwischen geändert hat.
Für die deutsche Übersetzung:
© 2002 Jürgen Katins
Der Copyright-Eigner stellt folgende Lizenzen zur Verfügung:
Nicht-freie Lizenz:
This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at http://www.opencontent.org/openpub/). Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.
Freie Lizenz:
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".