CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
บทที่ 4 คําสั่งสําหรับ Input และ Output ในการพัฒนาโปรแกรมประเภท application ในการทํางานแบบ text mode นัน้ ภาษา Java ไดจัด เตรียม class สําหรับทํางานเกี่ยวกับ input และ output ไวดังนี้ 4.1 การรับขอมูลผานทางคียบอรด ในการเขียนโปรแกรมเพื่อรับขอมูลผานทางคียบอรด โดยใชภาษา Java นัน้ มีหลักการทํางานเบื้องตน ดังนี้ ในการนําขอมูลเขา หรือ สงออกเพื่อแสดงผล เริ่มจาก Java จะเปด data stream และจัดการอานขอ มูลเขาโดยไมสนใจวา data stream นีต้ อ กับอุปกรณใด หลังจากนั้นจะทําการอาน หรือ เขียนขอมูล โดยขอมูล จะถูกอานหรือเขียนครั้งละ 1 byte เทานั้น เมื่อขอมูลถูกอานหรือบันทึกจนหมด data stream นัน้ จะถูกปด package ทีจ่ ดั การดาน Input / Output ที่สําคัญคือ java.io และ Java จะแบง class ในการจัดการ อานหรือเขียนขอมูล 2 ประเภท คือ character หรือ byte เหตุผลที่แยกออกเปน 2 class นี้ เนื่องจากขนาดของ character เทากับ 2 byte แบบ Unicode นัน่ เอง แตไมวาจะอานเปนแบบ character หรือ byte หลักการอาน หรือเขียนจะเหมือนกันโดยผาน data stream ในการรับขอมูลผานทางคียบอรด จะตองมีการจัดการกับความผิดพลาดที่อาจเกิดขึ้นในการประมวล ผล ซึง่ การจัดการเชนนี้ เรียกวา throwing the exception ทัง้ นีเ้ นือ่ งจากการเขียนโปรแกรมที่ดีตองไมให โปรแกรมหยุดทํางานกลางคันโดยไมทราบสาเหตุ ผูเขียนโปรแกรมจึงจําเปนตองเขียนโปรแกรมจัดการกับขอผิด พลาดเหลานัน้ เชน ในการหาคาเฉลี่ย ซึ่งตองมีการหารดวยตัวเลข ผูใชโปรแกรมอาจไมใสขอมูลใดๆ เลย หรือ อาจใส 0 ก็ได ซึ่งการหารดวยศูนยในทางคอมพิวเตอร จะไมสามารถหาผลลัพธได โปรแกรมจะใชตัว exception นีต้ รวจสอบขอผิดพลาดที่อาจเกิดขึ้นและแสดงใหผูใชงานทราบ 4.1.1
การรับคาผานคียบอรดอยางงาย ใน class System ซึง่ เปน class มาตรฐานของ Java มีการประกาศตัวแปร 3 ตัว คือ in, out และ err
ดังนี้ public static final InputStream in; public static final PrintStream out; public static fianl PrintStream err; ทัง้ 3 ตัวแปรถูกประกาศแบบ static และ final หมายความวา ตัวแปรเหลานี้ถูกเรียกผาน class โดย ไมจําเปนตองสราง object ในการรับขอมูล System.in จัดเปนมาตรฐานในการนําขอมูลเขาผานทางคียบอรดในลักษณะของ byte 2/2545
1
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ตัวอยางที่ 1 class KeybRead { public static void main (String args[]) { char buf = ‘\0’; try { buf = (char) System.in.read(); } catch (Exception e) { System.out.println (“Error:”+e.toString()); } System.out.println(“Your input data is “+buf); } }
System.in.read จะรับคาขอมูลผานทางคียบอรด โดยขอมูลที่อานเขามาจะเปน byte และแปลงเปน integer แตในตัวอยางที่ 1 พบวาตัวแปรที่รับคาจาก System.in.read มีชนิดเปน char ดังนัน้ จึงตองเพิ่ม (char) ไวหนา System.in.read เพือ่ เปนการแปลงขอมูลใหมีชนิดเปน character อีกทีหนึ่ง และผลจากการรับ ขอมูลในแบบของ character ทําใหตัวแปร buf จึงเก็บขอมูลเพียงอักษรตัวแรกที่บันทึกผานคียบอรดเทานั้น สําหรับการทํางานใน method read จะรอจนมีขอมูลเขา หรือรอจนผูใชบันทึกขอมูล และจะอานขอมูล เก็บไปเรื่อยๆ จนกระทั่งผูใชกดปุม Enter แลวจึงแปลงขอมูลใสหนวยความจําของผูใชตอไป ในสวนของการจัดการ throwing exception ทําไดดวยคําสั่ง try {…} catch {…} โดยใสคําสั่งอานขอ มูลใน block ของ try {…} สวนคําสั่งใน block ของ catch เปนคําสั่งในการจัดการ error ตางๆ ที่ไมคาดวาจะ เกิดขึน้ โดยสวนมากมักเปนการแสดงขอความบนจอภาพใหผูใชทราบถึงขอผิดพลาด ตัวอยางที่ 2 จะเปนตัวอยางสําหรับการรับขอมูลไดมากกวา 1 ตัวอักษร โดยใช System.in.read() โดยใช loop while ในการวนรับคาจนกระทั่งพบ '\n' หรือการกดคีย Enter นัน่ เอง ตัวอยางที่ 2 class KeybRead2 { public static void main (String args[]) { char buf = ‘\0’; StringBuffer bufOut = new StringBuffer(); try { while ((buf = (char)System.in.read()) != ‘\n’) { bufOut.append(buf); } } catch (Exception e) { System.out.println (“Error:”+e.toString()); } System.out.println(“Your input data is “+bufOut); } }
2/2545
2
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ในตัวอยางที่ 2 นี้จะพบวามีการประกาศ object ชื่อ bufOut จาก class StringBuffer ซึง่ โปรแกรมจะ ใช method append ที่อยูใน class นีใ้ นการเชือ่ มตัวอักษรตางๆ ที่รับจากผูใชผานทางคียบอรด 4.1.2
การรับขอมูลตัวเลขผานคียบอรด
สายอักขระที่รับผานคียบอรดนั้น สามารถใช method ใน class Integer และ Double ซึง่ เปน Type wrappers ในการเปลีย่ นขอมูลสายอักขระเปนจํานวนเต็ม และจํานวนจริง ตามลําดับ Type wrapper เปนกลุมของ class ที่อยูใน package java.lang ซึง่ มีชื่อเหมือนกับ primitive data type (เชน int หรือ double) แตละ class ของ type wrapper จะขึน้ ตนชื่อดวยตัวพิมพใหญ (เนื่องจากเปนชื่อ class ) เชน Integer หรือ Double โดยจะมี method ตางๆ ที่ใชในการจัดการกับขอมูล primitive data type เชน การ convert จาก String เปน integer ซึ่ง primitive data type ไมสามารถทําได ตัวอยางตอไปนี้ เปนการแสดงถึงคุณสมบัติหลักประการหนึ่งของการเขียนโปรแกรมแบบเชิงวัตถุ นั่น คือ การนํากลับมาใชใหม โดยเปนการสราง class InputBox เพือ่ รับขอมูลผานทางคียบอรดเทานั้น โดยจะมี method หลักที่ใชในการรับขอมูล ชื่อ getInput() และจะมีอีก 3 method คือ รับเปนจํานวนเต็ม (getInteger()) รับเปนจํานวนจริง (getDouble()) และรับเปนขอความ (getString()) ซึง่ เปนการเรียกใช method getInput() มา ทํางาน ตัวอยางที่ 3 class InputBox { public String getInput() { char buf = ‘\0’; StringBuffer bufIn = new StringBuffer(); try { while ((buf = (char) System.in.read()) != ‘\n’) { bufIn.append (buf); } } catch (Exception e) { System.out.println(“Error:” + e.toString()); } return bufIn.toString(); } public int getInteger() { int value = 0; boolean done = false; while (!done) { try { value = Integer.parseInt(getInput().trim()); done = true; } catch (NumberFormatException e) { System.out.println(“Input error, Try integer”); } } // end while return value; } // end getInteger
2/2545
3
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ตัวอยางที่ 3 (ตอ) public double getDouble() { double value = 0; boolean done = false; while (!done) { try { Double y = new Double(getInput()); value = y.doubleValue(); done = true; } catch (NumberFormatException e) { System.out.println(“Input error, Try double value”); } } // end while return value; } // end getDouble public String getString() { return getInput(); } // end getString } // class InputBox class KeybRead3 { public static void main (String args[]) throws Exception { InputBox input = new InputBox(); int noOfGuest; double rate; String party; System.out.print(“Enter your Party Name “); party = input.getString(); System.out.println(); System.out.print(“Enter number of guest “); noOfGuest = input.getInteger(); System.out.println(); System.out.print(“Enter Rate: ”); rate = input.getDouble(); System.out.println(); System.out.println(“Total Cost is “ + (rate * noOfGuest)); } // end of main } // end KeybRead3
จากตัวอยางโปรแกรมที่ 3 สามารถสรุปไดดังนี้ - getInteger() จะเปน method จัดการเปลี่ยนขอมูลที่รับผานคียบอรดเปนจํานวนเต็ม ในการ ทํางานของ method นี้ จะมีการตรวจสอบขอมูลที่รับเขามาวาเปนจํานวนเต็มหรือไม โดยมีขั้น ตอนการทํางานดังนี้ 1. การตรวจสอบขอมูลวาเปนจํานวนเต็มหรือไม ดวยคําสั่ง try{…} catch (e) {…} หากขอมูล เปนจํานวนเต็ม โปรแกรมจะ convert จาก string ใหเปน integer โดยใช Integer.parseInt
2/2545
4
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
(getInput().trim()); แตหากขอมูลไมใชจํานวนเต็ม โปรแกรมจะแสดงขอความบอกผูใชวาให พิมพเฉพาะจํานวนเต็มเทานั้น 2. เนื่องจาก class type wrapper Integer เปน static method ดังนั้นการ convert จาก string ใหเปน integer จึงสามารถเรียกใช method นีไ้ ดเลย ไมจําเปนตองสราง object กอน 3. กอนทีจ่ ะเปลีย่ นเปนจํานวนเต็ม ขอมูลจะถูกตัดชองวางในสวนทายออก (ถามี) ดวยคําสั่ง trim() ซึง่ เปน method ทีอ่ ยูใน class String -
-
4.1.3
getDouble() เปน method ในการรับขอมูลจํานวนจริง หลักการทํางานโดยทั่วไปจะเหมือนกับ method getInteger() แตการเปลี่ยนขอความเปนจํานวนจริงจะใช class ทีต่ างกัน คือ Double ซึง่ จําเปนตองสราง object กอนจึงจะสามารถเรียกใช method doubleValue() ได getString() เปน method ในการรับขอมูลที่เปนขอความใดๆ method ดังกลาวไมตองมีการจัด การใดๆ เนื่องจากขอมูลที่รับเขามาจาก method getInput() มีชนิดขอมูลเปนแบบ String อยูแลว
การรับขอมูลจากคียบอรดโดยใช BufferedReader
BufferedReader เปน sub-class ของ class Reader ซึง่ ใชในการอานขอมูลแบบ character โดยจะ อยูใน package java.io.* ในหัวขอที่ 4.1.1 และ 4.1.2 เปนการอานขอมูลโดยใช InputStream ซึง่ จะอานขอ มูลเปน byte ตัวอยางที่ 4 เปนการแสดงขั้นตอนในการเขียนโปรแกรมที่มีการใช buffer เพือ่ อานขอมูล การอาน จาก buffer จะประมวลผลไดรวดเร็วกวาการอานโดยตรง (System.in ไมมี buffer) และเรียกใช class Reader ซึง่ จะอานขอมูลเปน character เลย ดังไดกลาวมาแลวขางตน import java.io.*; public class KeybRead4 { public static void main (String args[] ) { InputStreamReader reader = new InputStreamReader(System.in); BufferedReader input = new BufferedReader(reader); String text = “ “; int aNumber = 0; System.out.print(“Enter no of guest: “); try { text = input.readLine(); aNumber = Integer.parseInt(text); System.out.print(“Enter rate: “); text = input.readLine(); } catch (Exception e) { System.out.println(e); System.exit(1); } Double x = new Double(text); double rate = x.doubleValue(); System.out.println(“The answer is “ + (rate * aNumber)); } }
2/2545
5
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ขัน้ ตอนการทํางานของ class BufferedReader แสดงดังในรูปขางลางนี้ input BufferedReader
InputStreamReader
InputStream
String readLine()
char read()
byte read()
System.in การทํางานของ class BufferedReader ยังตองผาน System.in ซึง่ เรียก method ของ InputStream เหมือนหลักการเดิม แตเพื่อไมตองเสียเวลาในการอานตัวอักษร และตองแปลงรหัสจาก byte เปน char จึงเรียก InputStreamReader ซึง่ เปน sub-class ของ class Reader มาชวยในการแปลงรหัส และ BufferedReader เปน buffer ในการอานขอมูลเปนชุด 4.1.4
การรับขอมูลจากคียบอรดโดยใช DataInputStream class DataInputStream เปน sub-class ของ class FilterInputStream และ class InputStream
class DataInputStream จะใหความสะดวกในการอานขอมูลพื้นฐานตางๆ ของ Java ตัวแปรที่ตอง ผานใหกับ class นี้ คือ System.in (InputStream) โดยมี method ในการอานขอมูลพื้นฐานตางๆ ดังนี้ 1. final String readLine() อานขอมูลตัวอักษรที่จบดวยการขึ้นบรรทัดใหม (\n) การกดปุม Enter (\r) หรือ จบแฟมขอมูล (EOF) 2. final int readInt() และ final long readLong() อานขอมูลจํานวนเต็ม 3. final float readFloat() และ final double readDouble() อานขอมูลจํานวนจริง 4. final int readUnsignedByte() อานจํานวนเต็มที่ไมรวมเครื่องหมาย อยางไรก็ตามเฉพาะ method readLine() เทานัน้ ที่ใชไดกับการอานขอมูลผานทางคียบอรด สวน method อืน่ ใชสําหรับการอานขอมูลในแฟมขอมูล (file) ทัง้ นี้เพราะ method อื่นๆ เชน readInt() จะอานขอมูล แบบจํานวนเต็ม ซึ่งจะกินเนื้อที่ของหนวยความจําขนาด 2 byte แตขอมูลที่รับผานคียบอรด จะเปนแบบ character เทานั้น
2/2545
6
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ตัวอยางที่ 5 import java.io.*; public class KeybRead5 { public static void main (String args[] ) { DataInput input = new DataInputStream(System.in); String text = “ “; int noOfguest = 0; double rate = 0; System.out.print(“Enter no. of guest: “); try { noOfguest = Integer.parseInt(input.readLine()); System.out.println(“no of guest “+ noOfguest); System.out.print(“Enter rate: “); Double x = new Double (input.readLine()); rate = x.doubleValue(); } catch (IOException e) { System.out.println(e); System.exit(1); } System.out.println(“the answer is “+(rate*noOfguest)); } }
4.2 การอาน – เขียนขอมูลผานแฟมขอมูล ( file ) การอานขอมูลจากแฟมขอมูล ใชหลักการเดียวกับการอานขอมูลจากคียบอรด แตเปลี่ยนอานขอมูล จากคียบอรด เปนแฟมขอมูล และเรียก class FileReader / FileWriter หรือ FileInputStream / FileOutputStream ซึง่ ใชสําหรับการอานและเขียนแฟมขอมูล หลักการเขียนโปรแกรมเพื่ออานหรือเขียนแฟมขอมูล ประกอบดวยขั้นตอน ดังนี้ 1. ประกาศแฟมขอมูล หรือ ระบุตําแหนงของแฟมขอมูล เชน directory ดวย class File 2. เปดแฟมขอมูลดวยคําสั่ง FileReader / FileWriter หรือ FileInputStream / FileOutputStream 3. อานขอมูล โดยจะขึ้นอยูกับเทคนิคในการอานแฟมขอมูล ถาตองการอานทีละบรรทัด ตองเรียก ใช class ที่มี method readLine() 4. ปดแฟมขอมูล close()
2/2545
7
CS313: Object-Oriented Programming
4.2.1
บทที่ 4: คําสั่งสําหรับ Input และ Output
การอานแฟมขอมูลที่ใช buffer ตัวอยางที่ 5
import java.io.*; public class ReadFile1 { public static void main(String args[]) { FileReader infile; BufferedReader in = null; String buf = null; boolean eof = false; try { // open file infile = new FileReader(“test1.txt”); in = new BufferedReader(infile); } catch (IOException e) { System.out.println(“File not found”); System.exit(1); } while (!eof) { try { buf = in.readLine(); if (buf == null) eof = true; else System.out.println(buf); } catch (IOException e) { System.out.println(“End of file”); } } } }
4.2.2
การอานและจัดเก็บแฟมขอมูลแบบระเบียน ตัวอยางที่ 6
import java.io.*; public class ReadFile2 { public static void main (String args[]) { FileReader infile; BufferedReader in = null; String buf = null; boolean eof = false; try { infile = new FileReader (“test2.txt”); in = new BufferedReader (infile); }
2/2545
8
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ตัวอยางที่ 6 (ตอ) catch (IOException e) { System.out.println(“File not found”); System.exit(1); } while (!eof) { try { buf = in.readLine(); if (buf == null) eof = true; else { String buf1; System.out.println(buf+” “+buf.length()); System.out.println(buf.substring(0,29)); System.out.println(buf.substring(30,59)); System.out.println(buf.substring(60,79)); System.out.println(buf.substring(80,109)); System.out.println(buf.substring(110,111)); } } catch (IOException e) { System.out.println(“End of file”); } } } }
สําหรับโครงสรางแฟมขอมูลของตัวอยางที่ 6 มีดังนี้ ชื่อหนังสือ char(30) ผูแตง char(30) เลขหมูหนังสือ char(20) สํานักพิมพ char(30) สถานะ char(2) ขอมูลจะถูกอานทีละ record (ทีละบรรทัด) ดังนั้นจึงตองมีการแยก field ซึง่ สามารถทําไดโดยใช method substring(int s, int e) ของ class String โดย s คือตําแหนงอักขระเริ่มตนของการอาน และ e คือ ตําแหนงอักขระสุดทายที่ถูกอาน 4.2.3
การอานขอมูลที่แตละ field แบงดวยชองวาง (space)
ในการอานขอมูลที่สามารถแยก field ดวยอักขระพิเศษ เชน เครื่องหมาย space หรือ comma ทําได โดยใช class StreamTokenizer
2/2545
9
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
การทํางานของ class นี้ จะอานขอมูลทีละ token (กลุม อักขระ) อีกทั้งสามารถแยกอักขระออกจาก กัน หากในอักขระดังกลาวประกอบดวยอักขระพิเศษที่ผูใชกําหนดในคําสั่ง commentChars(int c) โดยที่ c เปน รหัสอักขระพิเศษนั้น ถาเปนการคั่นดวยชองวาง ทําไดโดยเรียกใช method whitespaceChars(0,32); ตัวอยางที่ 7 import java.io.*; public class DemoStreamToken { public static void main (String args[] ) throws IOException { FileReader r = new FileReader(“test1.txt”); StreamTokenizer inStream = new StreamTokenizer ( r ); inStream.whitespaceChars(0,32); boolean eof = false; do { int token = inStream.nextToken(); switch (token) { case StreamTokenizer.TT_EOF : eof = true; case StreamTokenizer.TT_EOL : break; case StreamTokenizer.TT_WORD : System.out.println(“Word: “+inStream.sval); break; case StreamTokenizer.TT_NUMBER : System.out.println(“Number: “+inStream.nval); break; } } while (!eof); } }
4.2.4
การอานขอมูลและบันทึกขอมูลแบบ binary ตัวอยางที่ 8
import java.io.*; public class FileIOApp { public static void main (String args[]) throws IOException { File file = new File (“test.txt”); FileOutputStream outFile = new FileOutputStream(file); DataOutputStream outs = new DataOutputStream(outFile); outs.writeBoolean(true); outs.writeInt(950); outs.writeChar(‘a’); outs.writeDouble(2575.50); System.out.println(outs.size() + “byte were written”); outs.close(); outFile.close(); FileInputStream inFile = new FileInputStream(file); DataInputStream ins = new DataInputStream(inFile);
2/2545
10
CS313: Object-Oriented Programming
บทที่ 4: คําสั่งสําหรับ Input และ Output
ตัวอยางที่ 8 (ตอ) System.out.println(ins.readBoolean()); System.out.println(ins.readInt()); System.out.println(ins.readChar()); System.out.println(ins.readDouble()); ins.close(); inFile.close(); } }
การบันทึกขอมูลแบบ binary ไมสามารถเปดดูแฟมขอมูลโดยใช editor ดังนัน้ การอานขอมูลจึงจํา เปนตองใช method เฉพาะ เชน readInt() สําหรับการอานขอมูลแบบ integer ทีถ่ กู จัดเก็บแบบ binary 4.3 สรุปโครงสราง subclass ของ package java.io java.lang.Object File FileDescriptor InputStream ByteArrayInputStream FileInputStream FilterInputStream BufferedInputStream DataInputStream PushbackInputStream ObjectInputStream PipedInputStream SequenceInputStream
OutputStream ByteArrayOutputStream FileOutputStream FilterOutputStream BufferedOutputStream DataOutputStream PrintStream ObjectOutputStream PipedOutputStream
RandomAccessFile Reader BufferedReader LineNumberReader CharArrayReader FilterReader PushbackReader InputStreamReader FileReader PipedReader StringReader
Writer BufferedWriter CharArrayWriter FilterWriter OutputStreamWriter FileWriter PipedWriter PrintWriter StringWriter
2/2545
11