Java 101: Die Vor- und Nachteile der Standardeingabe / -ausgabe

In früheren Java 101- Artikeln habe ich auf die Konzepte der Umleitung, des Standardeingabegeräts und des Standardausgabegeräts verwiesen. Um die Eingabe von Daten zu demonstrieren, werden mehrere Beispiele genannt System.in.read(). Es stellt sich heraus, dass System.in.read()Daten vom Standardeingabegerät eingegeben werden. Um die Ausgabe von Daten zu demonstrieren, werden Beispiele mit System.out.print()und genannt System.out.println(). Im Gegensatz dazu senden System.in.read()diese Methoden - benannte Sequenzen von ausführbarem Code (die im Artikel des nächsten Monats behandelt werden) - ihre Ausgabe an das Standardausgabegerät. Möchten Sie mehr über Standard-E / A-Konzepte erfahren? Weiter lesen!

Standard I / O ist ein standardisierter Ein- / Ausgabemechanismus, der vom Unix-Betriebssystem stammt. Obwohl dieser Mechanismus hauptsächlich bei älteren Nicht-GUI-Betriebssystemen verwendet wird, spielt Standard-E / A in modernen GUI-Betriebssystemen (grafische Benutzeroberfläche) immer noch eine Rolle. Programmierkurse.

Wie Sie wahrscheinlich vermutet haben, verwendet Standard-E / A Geräte zum Eingeben und Ausgeben von Daten. Diese Geräte umfassen Standardeingabe, Standardausgabe und Standardfehler.

Standardeingabe

Das Standardeingabegerät ist der Teil des Betriebssystems, der steuert, von wo ein Programm seine Eingabe empfängt. Standardmäßig liest das Standardeingabegerät diese Eingabe von einem an die Tastatur angeschlossenen Gerätetreiber. Sie können die Eingabequelle jedoch auf einen an eine Datei angehängten Gerätetreiber umleiten oder umschalten, sodass die Eingabe "magisch" aus einer Datei zu stammen scheint - anstelle der Tastatur.

Ein Programm gibt seine Daten vom Standardeingabegerät durch Aufrufen der Java- System.in.read()Methode ein. In der SDK-Dokumentation finden Sie eine Klasse namens System. Diese Klasse enthält eine Variable namens in- ein Objekt, das aus einer Unterklasse von erstellt wurde InputStream. Das Punktzeichen nach SystemZuständen, zu denen es ingehört System, und das Punktzeichen nach inZuständen, zu denen es read()gehört in. Mit anderen Worten, read()ist eine Methode, die zu einem aufgerufenen Objekt gehört in, das wiederum zu einer aufgerufenen Klasse gehört System. (Ich werde nächsten Monat mehr über Klassen, Objekte und "Zugehörigkeit zu" diskutieren.)

System.in.read()Nimmt keine Argumente und gibt eine Ganzzahl zurück, was einige zu der Annahme veranlasst hat, dass vom System.in.read()Benutzer eingegebene Ganzzahlen zurückgegeben werden. Zur Verdeutlichung wird System.in.read()entweder der 7-Bit-ASCII-Code eines Schlüssels (wenn das Standardeingabegerät auf die Tastatur eingestellt ist) oder ein 8-Bit-Byte aus einer Datei (wenn das Standardeingabegerät von der Tastatur in eine Datei umgeleitet wurde) zurückgegeben. System.in.read()Konvertiert in beiden Fällen den Code in eine 32-Bit-Ganzzahl und gibt das Ergebnis zurück.

Angenommen, das Standardeingabegerät ist auf die Tastatur eingestellt. Im Folgenden wird beschrieben, was unter Windows geschieht: Wenn Sie eine Taste auf einer Windows-gesteuerten Tastatur eingeben, speichert das Betriebssystem den 7-Bit-ASCII-Code dieser Taste in einem internen Schlüsselpuffer. Dieser Schlüsselpuffer enthält bis zu 16 ASCII-Codes und ist als zirkuläre Warteschlangendatenstruktur für das Ein- und Aussteigen organisiert. System.in.read()Ruft den ASCII-Code vom Kopf des Schlüsselpuffers ab und entfernt diesen Code dann aus dem Schlüsselpuffer. Dieser 7-Bit-ASCII-Code wird dann in einen konvertiert, intindem dem System.in.read()Code 25 Null-Bits vorangestellt werden, und kehrt zum Aufrufer der Methode zurück. Ein zweiter System.in.read()Methodenaufruf ruft den nächsten ASCII-Code ab, der sich jetzt am Kopf des Schlüsselpuffers befindet, und so weiter.

Angenommen, der Schlüsselpuffer enthält keine ASCII-Codes. Was geschieht? System.in.read()Wartet darauf, dass der Benutzer die Tasten eingibt und den Terminator drückt. Unter Windows ist dieser Terminator der EnterSchlüssel. Durch Drücken von EnterWindows wird ein Wagenrücklaufcode (ASCII 13) gefolgt von einem neuen Zeilencode (ASCII 10) im Schlüsselpuffer gespeichert. Daher kann der Schlüsselpuffer mehrere ASCII-Codes enthalten, gefolgt von einem Wagenrücklauf und einem Zeilenumbruchzeichen. Der erste dieser Codes kehrt von zurück System.in.read(). Überprüfen Sie diese Aktivität, indem Sie die EchoAnwendung eingeben, kompilieren und ausführen . Der Quellcode wird in Listing 1 angezeigt.

Listing 1. Echo.java

// Echo.java-Klasse Echo {public static void main (String [] args) löst java.io.IOException {int ch; System.out.print ("Geben Sie einen Text ein:"); while ((ch = System.in.read ())! = '\ n') System.out.print ((char) ch); }}

Echo führt die folgenden Schritte aus:

  1. Ruft die System.out.print()Methode auf, die ein StringArgument benötigt, um eine Eingabeaufforderung auszugeben
  2. Aufrufe System.in.read()zur Eingabe von ASCII-Codes vom Standardeingabegerät als 32-Bit-Ganzzahlen
  3. Wandelt diese 32-Bit - Integer zu 16-Bit - Unicode - Zeichen durch die (char)Besetzung
  4. Ruft die System.out.print()Methode auf, die ein charArgument benötigt, um diese Unicode-Zeichen an das Standardausgabegerät zurückzugeben

Die letzten drei Schritte in den vorherigen vier Schritten finden in einer while-Schleife statt und werden fortgesetzt, bis ein neues Zeilenzeichen gelesen wird. Laufen , Echoso dass es Eingaben von der Tastatur und gibt an den Bildschirm, die folgenden Befehl Zeile: java Echo.

Obwohl System.in.read()niemals eine Ausnahme ausgelöst wird (eine Definition dieses Begriffs finden Sie im Thema Wortzählung in diesem Artikel), wird beim Festlegen des Standardeingabegeräts auf die Tastatur möglicherweise eine Ausnahme ausgelöst, wenn Sie das Standardeingabegerät von der Tastatur auf umleiten eine Datei. Angenommen, Sie leiten das Standardeingabegerät in eine Datei um und System.in.read()lesen Inhalte aus der Datei. Angenommen, die Datei befindet sich auf einer Diskette, und der Benutzer wirft diese Diskette während des Lesevorgangs aus. Wenn der Auswurf stattfindet, wird System.in.read()eine Ausnahme ausgelöst, die das Programm darüber informiert, dass es die Datei nicht lesen kann. Dies ist der Grund für das Anhängen der throws java.io.IOExceptionKlausel an den main()Methodenheader. (In einem zukünftigen Artikel werden Sie Ausnahmen, Ausnahmen und verwandte Konzepte untersuchen.)

Wie leiten Sie das Standardeingabegerät so um, dass die Eingabe aus einer Datei stammt? Die Antwort besteht darin <, in der Befehlszeile ein Kleinerzeichen einzufügen und diesem Symbol einen Dateinamen zu folgen. Geben Sie die folgende Befehlszeile ein, um zu sehen, wie das funktioniert:java Echo . The command line redirects the standard input device to a file called Echo.java. When Echo runs, because each line ends in a new-line character, only the first line of text in Echo.java appears on the screen.

Suppose you need a utility program that reads an entire file and either displays the file's contents on the screen, copies those contents to another file, or copies those contents to a printer. Unfortunately, the Echo program only performs that task until it encounters the first new-line character. What do you do? The answer to the problem lies in the Type application. Listing 2 provides the source code:

Listing 2. Type.java

// Type.java class Type { public static void main (String [] args) throws java.io.IOException { int ch; while ((ch = System.in.read ()) != -1) System.out.print ((char) ch); } } 

Type resembles Echo, however, there is no prompt, and the while loop tests against -1 (which indicates end of file) instead of \n (which indicates end of line). To run Type, issue the following command line: java Type . The contents of Type.java -- or whatever file is specified -- will display. As an experiment, try specifying java Type. What do you think will happen? (Hint: this program resembles Echo but doesn't end until you press Ctrl+C.)

Earlier, I mentioned that some programmers mistakenly think that System.in.read() returns a user-entered number. As you've just seen, that isn't the case. But what must you do if you want to use System.in.read() to retrieve a number? Take a look at the Convert application, whose source code is presented in Listing 3.

Listing 3. Convert.java

// Convert.java class Convert { public static void main (String [] args) throws java.io.IOException { System.out.print ("Please enter a number: "); int num = 0; int ch; while ((ch = System.in.read ()) != '\n') if (ch >= '0' && ch <= '9') { num *= 10; num += ch - '0'; } else break; System.out.println ("num = " + num); System.out.println ("num squared = " + num * num); } } 

Listing 3's Convert program prompts the user to enter a number (via System.out.print ("Please enter a number: ");). It reads these digits -- one at a time -- and converts each digit's numeric code to a binary number that is added to a variable called num. Finally, calls to System.out.println() output the value inside num and the square of that value to the standard output device.

Convert demonstrates the time-honored technique of using a while loop to test for a digit, premultiplying a variable by 10 (to make room for the incoming digit), converting a digit to its binary equivalent, and adding that binary equivalent to the variable. However, that technique is not a sound technique to use if you're writing a program for deployment in different countries as some countries use digits other than 0 through 9 -- such as Tamil digits. To make the program operate with other digits, you need to expand the if statement to test for those digits and modify the ch - '0' expression. Fortunately, Java simplifies that task by providing a Character class, which you'll explore in a future article.

Standard output

The standard output device is that part of the operating system that controls where a program sends its output. By default, the standard output device sends the output to a device driver attached to the screen. However, the output destination can be redirected to a device driver attached to a file or printer, which results in the same program displaying its findings on the screen, saving them in a file, or providing a hardcopy listing of the results.

You achieve standard output by calling Java's System.out.print() and System.out.println() methods. Except for the fact that print() methods don't output a new-line character after the data, the two method groups are equivalent. Methods exist to output Boolean, character, character array, double-precision floating-point, floating-point, integer, long integer, string, and object values. To demonstrate these methods, Listing 4 presents source code to the Print application.

Listing 4. Print.java

// Print.java class Print { public static void main (String [] args) { boolean b = true; System.out.println (b); char c = 'A'; System.out.println (c); char [] carray = { 'A', 'B', 'C' }; System.out.println (carray); double d = 3.5; System.out.println (d); float f = -9.3f; System.out.println (f); int i = 'X'; System.out.println (i); long l = 9000000; System.out.println (l); String s = "abc"; System.out.println (s); System.out.println (new Print ()); } } 

Listing 4 has probably triggered some questions for you. First, what is all that System.out. business doing in front of println()? Again, refer to the System class in the SDK documentation. The class contains a variable called out -- an object created from a class called PrintStream. The period character after System indicates that out belongs to System. The period character after out states that println() belongs to out. In other words, println() is a method that belongs to an object called out, which in turn belongs to a class called System.

The second question you might be asking yourself involves println() argument data types: how is it possible for the same println() method to be called with different types of argument data? The answer: because there are several println() methods in the PrintStream class. At runtime, the JVM knows which println() method to call by examining the number of method-call arguments and their data types. (Declaring several methods with the same name but different numbers of arguments and argument data types is known as method overloading. I will discuss that concept next month.)

Finally, you might be wondering about System.out.println (new Print ());. That method call illustrates the println() method, which takes an Object argument. First, the creation operator new creates an object from the Print class and returns a reference to -- also known as the address of -- that object. Finally, that address passes as an argument to the println() method, which takes an Object argument. The method converts the object's contents to a string and outputs that string. By default, the string consists of the name of the object's class, followed by an @ (at) character, followed by a hexadecimal-formatted integer that represents the object's hashcode. (I will present hashcodes and the conversion of objects to strings in an upcoming article.)

Compile Print.java and run the program by issuing the following command line: java Print. You should see nine lines of output. Redirect that output to the out.dat file by issuing the following command line: java Print >out.dat. You can now view the contents of the file.

The greater-than sign, >, indicates standard output redirection. Whenever you want to redirect the standard output device from the screen to a file or printer, specify that symbol followed by the file or printer name on the command line. For example, redirect Print's output to a Windows printer by issuing the following command line: java Print >prn.