Java 101: הכניסות והפלטים של קלט / פלט רגילים

במאמרים קודמים של Java 101 התייחסתי למושגים הפניה מחדש, התקן קלט סטנדרטי והתקן פלט רגיל. כדי להדגים הזנת נתונים, נקראו כמה דוגמאות System.in.read(). מתברר כי System.in.read()קלט נתונים ממכשיר הקלט הסטנדרטי. כדי להדגים הפקת נתונים, דוגמאות שנקראות System.out.print()ו System.out.println(). בניגוד לכך System.in.read(), שיטות אלה - רצפים של קוד הפעלה בשם (שייחקרו במאמר בחודש הבא) - שולחות את הפלט למכשיר הפלט הסטנדרטי. רוצה לדעת יותר על מושגי קלט / פלט סטנדרטיים? תמשיך לקרוא!

קלט / פלט רגיל הוא מנגנון קלט / פלט סטנדרטי שמקורו במערכת ההפעלה יוניקס. למרות שמנגנון זה משמש בעיקר עם מערכות הפעלה ישנות שאינן GUI, קלט / פלט סטנדרטי עדיין ממלא תפקיד במערכות הפעלה מודרניות (ממשק משתמש גרפי) של GUI, שם אנשים משתמשים בו לניפוי באגים בתוכניות לא תקינות וכדי ללמד קלט / פלט בכניסה- קורסי תכנות ברמה.

כפי שבוודאי ניחשתם, קלט / פלט רגיל משתמש במכשירים להזנת נתונים ולהפקתם. התקנים אלה כוללים קלט סטנדרטי, פלט רגיל ושגיאות סטנדרטיות.

קלט סטנדרטי

התקן הקלט הסטנדרטי הוא חלק ממערכת ההפעלה שולטת מאיפת תכנית מקבלת הקלט שלה. כברירת מחדל, התקן הקלט הסטנדרטי קורא את הקלט ממנהל התקן המחובר למקלדת. עם זאת, אתה יכול להפנות מחדש, או להחליף את מקור הקלט למנהל התקן המחובר לקובץ כך שנראה שהקלט "קסום" מגיע מקובץ - במקום מהמקלדת.

תוכנית מכניסה את הנתונים שלה ממכשיר הקלט הסטנדרטי על ידי קריאה System.in.read()לשיטת Java . חפש בתיעוד SDK ותגלה מחלקה שנקראת System. מחלקה זו מכילה משתנה הנקרא in- אובייקט שנוצר מתת-מחלקה של InputStream. הדמות Systemהתקופתית אחרי מצבים inששייכת אליה System, והתו התקופתי אחרי inמצבים read()ששייך in. במילים אחרות, read()האם שיטה השייכת לאובייקט נקראת in, אשר בתורה שייכת למחלקה הנקראת System. (אדון עוד בנושא שיעורים, חפצים ו"השתייכות לחודש הבא).

System.in.read()לא לוקח שום טיעונים ומחזיר מספר שלם, מה שהביא כמה להאמין System.in.read()שמחזיר מספרים שלמים שהוזנו על ידי המשתמש. לשם הבהרה, System.in.read()או מחזיר קוד ASCII של 7 סיביות למפתח (אם מכשיר הקלט הסטנדרטי מוגדר למקלדת) או בת 8 סיביות מקובץ (אם התקן הקלט הסטנדרטי הופנה מהמקלדת לקובץ). בשני המקרים, System.in.read()ממיר את הקוד למספר שלם של 32 סיביות ומחזיר את התוצאה.

נניח שהתקן הקלט הסטנדרטי מוגדר למקלדת. להלן תיאור מה קורה תחת Windows: כאשר אתה מקליד מקש במקלדת הנשלטת על ידי Windows, מערכת ההפעלה שומרת את קוד ה- ASCII של 7 סיביות במפתח במאגר מפתח פנימי. חיץ מפתח זה מכיל בערך 16 קודי ASCII והוא מאורגן כמבנה נתוני תור עגול ראשון / ראשון. System.in.read()מאחזר את קוד ASCII מראש מאגר המפתחות ואז מסיר קוד זה ממאגר המפתחות. אותו קוד ASCII בן 7 סיביות ואז ממיר ל- int- על ידי הכנסת System.in.read()25 סיביות אפס לקוד - וחוזר למתקשר לשיטה. System.in.read()קריאת שיטה שנייה מאחזרת את קוד ה- ASCII הבא, שעכשיו נמצא בראש מאגר המפתחות וכן הלאה.

נניח שאין קודי ASCII במאגר המפתח. מה קורה? System.in.read()ממתין למשתמש להקליד מקשים ולחץ על המסוף. תחת Windows, המסוף הזה הוא Enterהמפתח. לחיצה Enterגורמת ל- Windows לאחסן קוד החזרת מרכבה (ASCII 13) ואחריו קוד קו חדש (ASCII 10) במאגר המפתח. לכן, חיץ המפתח עשוי להכיל מספר קודי ASCII ואחריו החזרת מרכבה ותו בשורה חדשה. הראשון מאותם קודים חוזר מ System.in.read(). בדוק את הפעילות על ידי הקשה, הידור והפעלת Echoהיישום; קוד המקור שלו מופיע ברשימה 1.

רישום 1. Echo.java

// Echo.java class Echo {public static void main (String [] args) זורק java.io.IOException {int ch; System.out.print ("הזן טקסט כלשהו:"); בעוד ((ch = System.in.read ())! = '\ n') System.out.print ((char) ch); }}

Echo משלים את השלבים הבאים:

  1. קורא System.out.print()לשיטה, שלוקחת Stringויכוח, להוציא הודעה
  2. קורא System.in.read()להזנת קודי ASCII מהתקן הקלט הרגיל כמספרים שלמים של 32 סיביות
  3. ממיר את אותם מספרים שלמים של 32 סיביות לדמויות Unicode של 16 סיביות באמצעות (char)הצוות
  4. קורא System.out.print()לשיטה, שלוקחת charויכוח, להדהד את תווי ה- Unicode האלה למכשיר הפלט הסטנדרטי

שלושת השלבים האחרונים בארבעת השלבים הקודמים מתרחשים בלולאת זמן, וממשיכים עד לקרוא תו של שורה חדשה. כדי להפעיל Echoכך תשומות מהמקלדת והתפוקות למסך, להוציא את שורת הפקודה הבאה: java Echo.

אף על פי System.in.read()שמעולם לא זורק חריג (ראה נושא ספירת מילים במאמר זה לקבלת הגדרה של מונח זה), כאשר מכשיר הקלט הסטנדרטי מוגדר למקלדת, הוא עשוי להשליך חריג כאשר אתה מפנה את התקן הקלט הסטנדרטי מהמקלדת אל קובץ. לדוגמה, נניח שאתה מפנה את התקן הקלט הסטנדרטי לקובץ System.in.read()וקורא תוכן מהקובץ. עכשיו נניח שהקובץ ממוקם על גבי תקליטון, והמשתמש מוציא את הדיסק הזה במהלך פעולת הקריאה. כאשר הפליטה מתבצעת, System.in.read()זורק חריג ומודיע לתוכנית שהיא אינה יכולה לקרוא את הקובץ. זה מספק את הסיבה לצירוף throws java.io.IOExceptionהסעיף main()לכותרת השיטה. (תחקור חריגים, השלכת חריגים ומושגים קשורים במאמר עתידי.)

איך מפנים את מכשיר הקלט הסטנדרטי כך שהקלט מקורו בקובץ? התשובה היא להציג סימן פחות מ- <, בשורת הפקודה ולעקוב אחר הסמל עם שם קובץ. כדי לראות כיצד זה עובד, הוציא את שורת הפקודה הבאה: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.