Important Announcement
PubHTML5 Scheduled Server Maintenance on (GMT) Sunday, June 26th, 2:00 am - 8:00 am.
PubHTML5 site will be inoperative during the times indicated!

Home Explore Basic Java

Basic Java

Published by chartsuwun, 2017-04-25 04:13:28

Description: Basic Java

Search

Read the Text Version

บทท่ี 7 การตรวจสอบและดักจับ error (Exceptions) 196เร่ิมตน กบั JavaEnter a divider: 0Exception: / by zerojava.lang.ArithmeticException: / by zero at ThrowsWithTry.main(ThrowsWithTry.java:27)Enter a number: 12Enter a divider: 3Result = 4.0Enter a number: popException in thread \"main\" java.lang.NumberFormatException: For inputstring: \"pop\" atjava.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:426) at java.lang.Integer.parseInt(Integer.java:476) at ThrowsWithTry.main(ThrowsWithTry.java:20)จากผลลัพธที่ไดจ ะเหน็ วา โปรแกรมของเราจะฟอ งถามกี ารหารดว ยศูนย และหยดุ ถา ขอ มูลไมใช int (ในตัวอยา งนผี้ ใู ชใ สค ําวา \"pop\") โปรแกรมของเราจะทํางานไปเร่อื ย ๆ ถาผใู ชใ สขอ มลู ทีถ่ กู ตอ งตามที่โปรแกรมไดก ําหนดไว แตน ไี่ มใ ชการตรวจสอบทีด่ ีเทา ไรนกั ถา เราตองการที่จะบอกผใู ชว า ขอ มูลไมถกู ตอ ง และใหใ สข อ มลู ใหมเ ราก็ตอ งแกไข code ของเราใหรองรับการทาํ ใหม ซึง่ อาจทําไดด ังนี้//ThrowsWithTry1.javaimport java.io.*;import java.lang.Integer;class ThrowsWithTry1 { public static void main(String[] args) throws IOException { BufferedReader buffer; InputStreamReader isr; String input; int first = 0, divider = 0; while(true) { System.out.print(\"Enter a number: \"); isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //get first number input = buffer.readLine(); first = readInt(input); //get second number only if first number is valid if(first != -1) { System.out.print(\"Enter a divider: \"); input = buffer.readLine(); divider = readInt(input); } //perform division if both numbers are valid if(first != -1 && divider != -1) { try { double result = first / divider; System.out.println(\"Result = \" + result); } catch(ArithmeticException e) { System.out.println(\"Exception: \" + e.getMessage()); ภาควิชาคอมพิวเตอรธรุ กจิ วทิ ยาลัยฟารอีสเทอรน

บทที่ 7 การตรวจสอบและดกั จับ error (Exceptions) 197เร่ิมตนกับ Java e.printStackTrace(); } } } } //method to convert an int from a string public static int readInt(String in) throws IOException { try { int num = Integer.parseInt(in); return num; } catch(NumberFormatException e) { System.out.println(\"Exception caught: \" + e.getMessage()); return -1; } }}เราไดเขยี น method readInt() สําหรบั การเปลี่ยน string ท่อี านจาก buffer ใหเปน int โดยเราไดใ ช tryและ catch ในการตรวจสอบและดักจับ error ที่อาจเกดิ ขึน้ จากการใสข อ มลู ผดิ พลาดทีอ่ าจเกดิ ข้ึนของผูใช และเรากาํ หนดใหส งคา -1 กลบั ออกไปเพือ่ ใชเ ปนตัวบอกให code ใน while loop รูวา ขอมูลไมถกู ตอ ง เพือ่ ทเี่ ราจะไดไ มต องอานขอมลู ตัวทสี่ อง ในสว นของ code ใน while loop เราไดท าํ การเปลี่ยนแปลงการอาน และ การประมวลผลใหเ ปน//get second number only if first number is validif(first != -1) { System.out.print(\"Enter a divider: \"); input = buffer.readLine(); divider = readInt(input);}//perform division if both numbers are validif(first != -1 && divider != -1) { try { double result = first / divider; System.out.println(\"Result = \" + result); } catch(ArithmeticException e) { System.out.println(\"Exception: \" + e.getMessage()); e.printStackTrace(); }}โปรแกรมของเราจะทําการประมวลผลถา ขอ มลู ทง้ั สองเปนขอมลู ท่ีถกู ตอง ดงั นนั้ เราจงึ ตองทําการตรวจสอบวา first และ divider มีคา ทถี่ ูกตองหรือไมดว ยการตรวจสอบกับ -1 ซึง่ ถา ตรวจสอบแลวไดขอมูลที่ถูกตอ ง เราก็จะทาํ การประมวลผลขอ มูลท้ังสอง ลองมาดผู ลลพั ธก ันEnter a number: 23Enter a divider: 3Result = 7.0Enter a number: pException caught: For input string: \"p\"Enter a number: 3Enter a divider: pException caught: For input string: \"p\"Enter a number: 32Enter a divider: 0 ภาควิชาคอมพิวเตอรธ ุรกิจ วทิ ยาลยั ฟารอ ีสเทอรน

บทท่ี 7 การตรวจสอบและดกั จบั error (Exceptions) 198เรมิ่ ตน กับ JavaException: / by zerojava.lang.ArithmeticException: / by zero at ThrowsWithTry1.main(ThrowsWithTry.java:34)Enter a number: -1Enter a number: Exception caught: nullEnter a number:จะเหน็ ไดวา โปรแกรมของเราทาํ งานไดอยา งทไ่ี ดต ั้งใจไว คอื ตรวจสอบขอ มลู ทง้ั สอง พรอ มทั้งทาํ การประมวลผลถา ขอ มลู ทั้งสองถกู ตอ ง ผอู า นควรสงั เกตดวยวา โปรแกรมตวั อยา งนยี้ งั ไมส มบรณู เลยทีเดยี วดงั จะเหน็ ไดจ ากการใสขอ มลู ที่เปน -1 ทาํ ไม? พรอ มกันนี้เรายงั ไมส ามารถออกจากโปรแกรมได ถาไมใ ชคําสั่ง <crtl> + cในการเขียนโปรแกรมทตี่ องรองรบั การทํางานทม่ี กี ารตรวจสอบเพ่ือใหเ กิดความถูกตองนั้น เราตองคาํ นึงถงึ ปจ จัยหลายดา น ท้ังนีก้ ข็ ้ึนอยูก บั ลักษณะของงานทเ่ี ราตอ งเขยี นโปรแกรมรองรบั โปรแกรมตวั อยา งของเราตองการแสดงใหเห็นถึงการตรวจสอบและดกั จับ error และแกไขในระดับหนึ่งเทาน้นัดังนน้ั ผูเขยี นจงึ ไมไดแสดงถงึ การแกไ ขท้ังหมด เพราะขอ กาํ หนดของงานยงั ไมชดั เจนการสรา ง exception ข้นึ มาใชเองJava ยอมใหเราสรา ง exception ขน้ึ มาใชกับโปรแกรมตา ง ๆ ท่ีเราคดิ วานาจะเพ่มิ ขอมูลบางอยา งใหกับผใู ช ถาหากมี error เกิดขึน้ เชน การหารดว ยศูนยท ีเ่ ราไดเ ขียนข้ึนมากอ นหนา นี้ เราอาจตองการบอกรายละเอยี ดใหม ากกวาเดมิ แกผ ใู ช เราจะใชโปรแกรมการหารดวยศนู ยที่มกี ารเปลยี่ นแปลงบางอยา ง เปนตวั อยา งตอ ไป//TestInputValidation.javaimport java.io.*;import java.lang.Integer;class TestInputValidation { public static void main(String[] args) throws Exception { BufferedReader buffer; InputStreamReader isr; String input; int first, divider; while(true) { //get first number first = readInt(); //get second number only if first number is valid divider = readInt(); //perform division if both numbers are valid try { //calling method divide() int result = divide(first,divider); System.out.println(\"Result = \" + result); } //catching user defined exception catch(ZeroDivideException e) { e.printStackTrace(System.err); } } } //method to get an int from the keyboard ภาควิชาคอมพิวเตอรธุรกจิ วทิ ยาลยั ฟารอ สี เทอรน

บทท่ี 7 การตรวจสอบและดักจบั error (Exceptions) 199เริ่มตนกบั Java public static int readInt() throws Exception { BufferedReader buffer; InputStreamReader isr; String input = null; int result = 0; boolean ok = false; isr = new InputStreamReader(System.in); buffer = new BufferedReader(isr); //keep looping until user enter an int while(!ok) { System.out.print(\"Enter a number: \"); try { input = buffer.readLine(); result = Integer.parseInt(input); ok = true; } catch(NumberFormatException e) { System.out.println(e.getMessage()); e.printStackTrace(System.err); } } return result; } //method to divide first number by the second number public static int divide(int first, int second) throws ZeroDivideException { int result; try { result = first / second; } catch(ArithmeticException e) { throw new ZeroDivideException(); //throw new exception } return result; }}เราไดเปลี่ยนโปรแกรมกอนหนา นม้ี ากพอสมควรในการทีจ่ ะอานขอมูลใหถกู ตอง พรอมทง้ั แสดงถงึ การเขียน exception ขนึ้ มาใชเอง เราเริ่มดวยการสราง method readInt() ขึน้ มาใหม โดยกําหนดใหผ ูใชตอ งใสขอ มลู ใหถ กู ตอ ง ถา ไมถูกเราก็จะวนกลบั ไปถามใหมจ นกวา จะไดMethod ตัวทส่ี องทีเ่ ราสรางขนึ้ มาคือ method divide() ทีร่ บั parameter 2 ตัว ทําหนาทใ่ี นการหารตัวเลขตัวแรกดว ยตัวเลขตัวทสี่ อง ภายใน method divide() นี้เราจะดกั จบั error ที่เกิดขนึ้ ผานทางArithmeticException ดว ย การ throw exception ท่ีเราไดส รา งข้นึ เอง ดวยคําสั่งcatch(ArithmeticException e) { throw new ZeroDivideException(); //throw new exception}แตก อนทีเ่ ราจะเรยี กใช exception ทีว่ านี้เราตอ งสรา ง code สําหรับ exception เสยี กอ น ซง่ึ เราไดออกแบบใหเ ปน การดักจับแบบงา ย ๆ ดวยการสราง class ZeroDivideException จาก class Exceptionเพ่อื ท่ีจะใหเราสามารถทจี่ ะไดร บั การถา ยทอดคุณสมบัติจาก class Exception เรากาํ หนดให code ของclass ZeroDivideException มีดงั นี้//ZeroDivideException.java ภาควิชาคอมพิวเตอรธ รุ กิจ วทิ ยาลยั ฟารอสี เทอรน

บทที่ 7 การตรวจสอบและดักจับ error (Exceptions) 200เริม่ ตนกับ Javaclass ZeroDivideException extends Exception { //default constructor ZeroDivideException() { super(\"divide by zero\"); //call super class' constructor } ZeroDivideException(String message) { super(message); }}เราไมไ ดทาํ อะไรมากไปกวาเรยี กใช constructor ของ class Exception ดว ยขอความที่เราตองการใหปรากฏหาก error ท่วี าน้เี กิดขน้ึ (divide by zero)ภายในตัว method main() เอง code สวนทสี่ ําคญั คือtry { //calling method divide() int result = divide(first,divider); System.out.println(\"Result = \" + result);}//catching user defined exceptioncatch(ZeroDivideException e) { e.printStackTrace(System.err);}เราเรยี ก method divide() ภายใน try และถาหากการหารท่ีเกดิ ขึน้ มี error มนั ก็จะถูกจบั ใน catch blockทีเ่ ราไดเ รยี กดว ย object ทีม่ าจาก class ZeroDivideException ทเ่ี ราไดส รา งขน้ึ หลังจากทีล่ อง run ดูเราไดผลลัพธด งั นี้Enter a number: 45Enter a number: 36Result = 1Enter a number: 0Enter a number: 3Result = 0Enter a number: popFor input string: \"pop\"java.lang.NumberFormatException: For input string: \"pop\" atjava.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Integer.parseInt(Integer.java:426) at java.lang.Integer.parseInt(Integer.java:476) at TestInputValidation.readInt(TestInputValidation.java:47) at TestInputValidation.main(TestInputValidation.java:16)Enter a number: 3Enter a number: 0ZeroDivideException: divide by zero at TestInputValidation.divide(TestInputValidation.java:64) at TestInputValidation.main(TestInputValidation.java:23)Enter a number: null (เราออกจากโปรแกรมดว ยการกด <crtl> + c ณ ตําแหนง นี้)java.lang.NumberFormatException: null at java.lang.Integer.parseInt(Integer.java:394) at java.lang.Integer.parseInt(Integer.java:476) ภาควิชาคอมพิวเตอรธ รุ กจิ วิทยาลยั ฟารอสี เทอรน

บทที่ 7 การตรวจสอบและดักจบั error (Exceptions) 201เรม่ิ ตนกับ Java at TestInputValidation.readInt(TestInputValidation.java:47) at TestInputValidation.main(TestInputValidation.java:16)Enter a number:ผลลัพธท ไ่ี ดกเ็ ปนไปตามทีเ่ ราไดคาดไว คอื error ถกู ดกั จับไวไ ดห มด ผูอานควรสังเกตดว ยวาเรายังใชloop ใน method main() ดังนั้นการออกจาก loop กต็ อ งใช <crtl> + c เหมอื นเดิม ทาํ ใหมกี ารดกั จับerror ท่เี กิดข้นึ ครัง้ สดุ ทา ยกอนออกจากโปรแกรมอกี สว นหน่งึ ทน่ี า สนใจในโปรแกรมของเรากค็ อื การสง ขอความบอกถึงรายละเอียดของ error ผา นทางSystem.err ซึ่งเปน อกี ชอ งทางหนึง่ ท่ี Java มใี หใชส าํ หรับการสงขอ มลู ทไ่ี มใชข อ มลู ปกติออกทางหนา จอ ถงึ แมว า ขอมูลจะออกไปท่ีเดยี วกันแตช องทางการสง ออก ไมเหมอื นกัน สาเหตทุ ี่เปน เชน น้กี ็เพอ่ื ใหม ีการแยกแยะ error ออกจากขอมูลหรือผลลัพธป กตขิ องโปรแกรมเรามาดอู กี สกั ตวั อยา งหนึง่//CheckRange.javaimport java.lang.Integer;class CheckRange { public static void main(String[] args) { try { //getting input from argument list int first = Integer.parseInt(args[0]); int second = Integer.parseInt(args[1]); int third = Integer.parseInt(args[2]); //check if the third input is between first and second checked(first, second, third); System.out.println(\"Number \" + third + \" is in the given range\"); } catch(OutOfRangeException e) { e.printStackTrace(System.err); } } //method to validate range public static void checked(int start, int stop, int num) throws OutOfRangeException { if(num < start) { String errMsg = new String(num + \" < \" + start); throw new OutOfRangeException(errMsg, start, stop); } if(num > stop) { String errMsg = new String(num + \" > \" + stop); throw new OutOfRangeException(errMsg, start, stop); } }}โปรแกรมตวั อยา งนีร้ ับขอ มูลผา นทาง argument list ท่ีเปน ตวั เลขสามตัว โดยจะทําการตรวจสอบวาตวั เลขตัวทสี่ ามอยูร ะหวางตวั แรกและตวั ทสี่ องหรือไม ถา ไมกจ็ ะ throw exceptionOutOfRangeException ที่ไดเ ขียนขึน้ ดังนี้//OutOfRangeException.java ภาควิชาคอมพิวเตอรธ รุ กิจ วทิ ยาลยั ฟารอีสเทอรน

บทท่ี 7 การตรวจสอบและดกั จับ error (Exceptions) 202เริม่ ตนกบั Javapublic class OutOfRangeException extends Exception { //default constructor OutOfRangeException() {} //constructor OutOfRangeException(String message, int p, int q) { super(message); }}จะเหน็ วา โดยสว นใหญแ ลว เราจะเรียกใช super class constructor ใหทํางานใหเ รา มากกวา ที่จะเขยี นcode ข้ึนมา ซงึ่ เปน ส่งิ ทที่ าํ ใหก ารออกแบบของเราไวขึน้ เราเพยี งแตเขยี นถึงสิ่งท่บี งบอกถงึ error ทีเกิดขน้ึ วาเปน อะไรเทานัน้ เอง จากการ run ผลลัพธท ี่เราไดค อื>java CheckRange 12 45 569OutOfRangeException: 569 > 45 at CheckRange.checked(CheckRange.java:31) at CheckRange.main(CheckRange.java:15);E:\bc221Book\source>java CheckRange 12 45 2OutOfRangeException: 2 < 12 at CheckRange.checked(CheckRange.java:27) at CheckRange.main(CheckRange.java:15)E:\bc221Book\source>java CheckRange 12 45 15Number 15 is in the given rangeสรปุในการเขยี นโปรแกรมที่ดนี นั้ ผเู ขยี นจะตอ งคาํ นงึ ถงึ error ที่อาจเกิดขน้ึ ในโปรแกรม ซง่ึ ไดแบง ออกเปนสองลกั ษณะใหญ คือ error ทโ่ี ปรแกรมเมอรไ มม ที างแกไ ขได คอื อยนู อกเหนือการควบคมุ ของผพู ฒั นาโปรแกรม เชน error ที่เกิดจากหนว ยความจาํ ไมพอเพยี ง สว น error อีกอันหน่ึงทผี่ เู ขียนโปรแกรมตอ งตรวจสอบกค็ ือ error ทเ่ี กดิ ตอน run โปรแกรม เชน error จากการหารดว ยศนู ย การเขา หาIndex ของ array ที่ไมมีอยูจ รงิ การปอนขอมลู ท่ีไมถกู กับชนดิ ทต่ี องการ อยา งนเี้ ปน ตนException ท่ี Java มใี หม อี ยมู ากพอสมควร และมากพอทจี่ ะเรียกใชไดเ กือบทกุ กรณีของการเขียนโปรแกรม แตถ า ผูเขยี นโปรแกรมไดพฒั นาโปรแกรมท่ีไมส ามารถใช exception ท่ี Java มใี หก ส็ ามารถท่ีจะออกแบบ exception ข้นึ มาใชเ องไดในการดัก error นัน้ ผเู ขียนอาจสรา ง exception ขึน้ มาใชใ นการดักจบั error เองได ทั้งนีก้ ็ข้นึ อยกู ับลกั ษณะของงานที่ผูเขยี นโปรแกรมกําลงั พฒั นาอยู โดยสรุปแลวสงิ่ ทตี่ อ งควรคํานงึ ในการตรวจจบั errorคือ9 Exception เปนตวั บง ชถี้ ึง error ทเี่ กดิ ในโปรแกรม9 Exception เปน object ท่เี กิดมาจาก class Throwable9 เราสามารถทจี่ ะเรยี กใช exception ทม่ี าจาก Java โดยตรง หรอื สรา งขึ้นมาใชเ อง9 ถา เราตองการทจี่ ะควบคมุ exception ใน method เราตอ งเขยี น code ใน try block และไมจ าํ เปนที่ จะตองมี try block เพียงหนง่ึ block เทาน้ัน อาจมีมากกวา หน่ึง block ได9 Code ทใ่ี ชใ นการควบคุม หรอื แกไ ข exception จะตอ งทําใน catch block ทต่ี ามหลงั try block ทันทแี ละในหนง่ึ try block เราสามารถที่จะมี catch block มากกวา หนึง่ ตัวได9 Finally เปน block ทายสดุ ทอ่ี ยูใ น try โดยทวั่ ไปจะใช finally block ในการเก็บกวาดการทาํ งานของ โปรแกรม เชน การปดไฟล ภาควิชาคอมพิวเตอรธ ุรกจิ วทิ ยาลยั ฟารอ สี เทอรน

บทที่ 7 การตรวจสอบและดักจบั error (Exceptions) 203เร่มิ ตนกบั Javaแบบฝก หดั1. จงเขียนโปรแกรมทรี่ บั ขอ มูลจาก keyboard เฉพาะท่ีเปน int เทา นน้ั ใหใ ช exception ในการดักจบั error ทผี่ ูใชอาจใสผ ดิ เชน ใสต ัวอักษร ใหแ สดงขอความฟองทันทที ผ่ี ูใชใสผ ิด2. จงปรบั ปรงุ โปรแกรมทเี่ ขยี นขนึ้ ในขอหนึ่ง โดยเพ่ิมการตรวจสอบท่ไี มร ับตัวเลขทต่ี ่าํ กวาศนู ย3. จงเขียนโปรแกรมทรี่ บั ขอ มูลจาก keyboard เปนตวั เลขสามตวั โดยกาํ หนดให ตวั แรกเปน จดุ เร่ิมตน ตวั ทสี่ องเปน จดุ จบ ของคาขององศา Celsius และตวั ทส่ี ามเปน ตัวกําหนดการเพ่ิมคา (step) ให โปรแกรมทาํ การคํานวณหา องศา Fahrenheit ตามขอมูลท่ีกาํ หนดไวในสองตวั แรก และใหท ําการ เพิ่มข้ึนตามคา ของขอมูลตัวทส่ี าม ดงั ตัวอยา งผลลัพธท ่ีแสดงใหด ูนี้>java Temperature 0 100 10CELSIUS FAHRENHEIT0 32.010 50.020 68.030 86.040 104.050 122.060 140.070 158.080 176.090 194.0100 212.0ใหท าํ การตรวจสอบ และดกั จบั error ทอ่ี าจเกิดขึ้นจากการใสขอ มูลทีไ่ มถ กู ตอ ง เชน คาของการเพิ่มเปน ตวั เลขทนี่ อ ยกวา ศูนย (negative number) คา เร่มิ ตน มากกวาคา สดุ ทา ย และจาํ นวนขอ มลู ท่ีนําเขามีจํานวนไมครบตามท่กี าํ หนด ตวั อยา งของ error ทีเ่ กิดข้ึน >java Temperature 0 100 -5 3rd arg < 0 NUMBER = -5 >java Temperature 40 20 5 Ordering Err FIRST = 40 SECOND = 20 >java Temperature 10 40 java.lang.ArrayIndexOutOfBoundsException: at Temperature.main(Temperature.java:41)4. จงเขียนโปรแกรมทหี่ าคา ของ mn โดยกําหนดใหท ั้ง m และ n มาจาก command line argument list ใหทําการตรวจสอบและดกั จับ error ทกุ ๆ กรณที ่ีอาจทาํ ใหโปรแกรมไมทาํ งาน5. จงปรับปรงุ class Account ในบททห่ี กใหมกี ารตรวจสอบและดกั จับ error ทอ่ี าจเกดิ ข้นึ ในการ ถอน เงิน ฝากเงิน และ คดิ ดอกเบย้ี ถา method ใด ๆ ทท่ี าํ หนาทด่ี ังกลาวไมม ี ใหเ ขียนข้นึ ใหม พรอ มทั้ง เขียนโปรแกรมทดสอบ6. จงปรบั ปรงุ โปรแกรมในขอ เจด็ แปด และ เกา ในบททหี่ า ใหมกี ารตรวจสอบและดกั จับ error พรอ ม ทัง้ เขยี นโปรแกรมทดสอบ ภาควิชาคอมพิวเตอรธรุ กจิ วิทยาลัยฟารอสี เทอรน

ในบทท่แี ปดนเ้ี ราจะพดู ถึงการอา น และเขยี นขอ มลู ผา นทาง stream หรอื ชอ งทางการสง ขอ มูล เราจะดถู งึวธิ ีการ กระบวนการตาง ๆ ทเ่ี กย่ี วของกับขอมูลนําเขา และการนําขอมูลออกหลงั จากจบบทน้ีแลว ผูอา นจะไดทราบถงึ o ความหมายของ stream o Class ตา ง ๆ ท่ี Java มีใหใ นการประมวลผลดว ย stream o การสรา ง directory o การสรา ง file การเปดและปด file การอา นและเขยี น file o ขอ แตกตางระหวาง text file และ binary fileในการทํางานทเี่ ก่ียวของกับไฟลใ น Java นั้นจะตองทาํ ผา นทาง stream ซึ่งเปนตวั แทนของอุปกรณท ่ีนาํ เขา (input) หรอื สง ออก (output) ขอ มูล เราสามารถเขียน และอานขอ มลู ผานทาง stream ดว ยวิธกี ารตาง ๆ ในรปู แบบตา ง ๆ กัน เชน อา นขอ มลู จาก keyboard ทีละหน่งึ ตัวอกั ษร หรอื ทลี ะ 10 byteโดยทว่ั ไป ขอมลู นําเขาจะมาจาก keyboard หนว ยความจําสาํ รอง (disk) หรอื อปุ กรณอ น่ื ๆ เชนscanner light-pen memory-card แตโดยสว นใหญแ ลวมักจะมาจาก keyboard และ disk ในบทนี้เราจะใชอ ปุ กรณทงั้ สองท่ีไดกลาวมา เปนชอ งทางหลกั ในการนาํ เขา ขอมลู และจะใชช อ งทางสง ออกเพยี งสองทางคือ จอ (monitor) และ เครอื่ งพมิ พ (printer)รูปแบบพืน้ ฐานของขอมลู ท่ี Java รจู กั มีอยสู องลกั ษณะคอื binary streams และ character streams ซง่ึมคี วามแตกตางกันในรปู แบบของการจดั เก็บ ถาเราเขียนขอมลู เขาสู stream โดยเขยี นทลี ะ byte หรือ ทีละหลาย ๆ byte เราเรียกขอ มลู เหลา น้วี า binary data การเขยี นจะไมม ีกระบวนการอื่นใดมายงุ เกี่ยว (เชนการเปลยี่ นขอมลู ใหอ ยใู นรปู แบบอืน่ กอ นการจดั เกบ็ ) ขอ มูลจะถูกสง เขา สู stream ตามทปี่ รากฏอยใู นmemory เชน ถา memory สว นนเ้ี ก็บขอ มูลท่เี ปน ตวั เลขอยู ตัวเลขเหลานจี้ ะถูกสง เขา สู streams ตามที่ปรากฏใน memoryในการเกบ็ ขอมลู ทีเ่ ปน character streams นน้ั โดยทวั่ ไปจะทํากบั ขอ มูลทีเ่ ปนตัวอกั ษร (text) เราจะใชcharacter streams ในการอา นไฟลทเี่ ปน text ตัวเลขทอ่ี ยูในไฟลจ ะถูกเปล่ียนใหอยใู นรปู แบบท่ี Javaไดก ําหนดขึ้น การอา นตวั เลขดว ยการใช character streams เปนกระบวนการทย่ี งุ ยากมาก เพราะเราตอ งรวู า ตวั อักษรที่เปน ตวั แทนของตวั เลขนั้นใชก ตี่ วั อกั ษรในการเก็บ เชน ถา เราสง ตวั เลข 17 ผา นทางcharacter stream ตัวเลขนี้จะถูกเปลี่ยนใหเ ปนคา ASCII ของ '1' และ '7' หรือ 0x310x37 (เลขฐาน 16)และสมมตวิ า เราเขียนเลข 727 อกี ตวั ใน stream ของเราก็จะมขี อมูลเปน 0x310x370x370x320x37 การอานตัวเลขทัง้ สองตัวออกมาจะทาํ ไดย ากมากเพราะเราไมรวู า จะตอ งอานตวั อักษรทลี ะก่ตี วั ถงึ จะไดข อ มลูท่ีถกู ตองเหมอื กับที่ไดเขยี นไวเราไดทราบแลว วา Java เกบ็ ขอ มลู ในรูปแบบของ Unicode ดังนัน้ ในการเขยี นขอ มูลเขาสู stream ในรปู แบบของ character ขอ มูลจะถูกเปลยี่ น (โดยอตั โนมตั )ิ ใหอยใู นรปู แบบของการเกบ็ (local code)ตามท่ีเคร่อื งนัน้ ใชอ ยู เชน ถา เคร่ืองของเราใชภ าษาไทยเปน ภาษาหลกั รปู แบบของการเก็บกจ็ ะเปน codeของภาษาไทย (Java เรยี กระบบนีว้ า localization) ในการอา นขอ มูลนัน้ Java จะเปลย่ี นขอ มูลทีถ่ ูกจัดเก็บในรปู แบบของ local code ใหเ ปน Unicode กอน โดยสรุปแลว ในการเขยี นและอานน้นั Java จะเปล่ียนขอมลู ใหเปน Unicode สว นการจดั เกบ็ น้นั จะจัดเกบ็ ในรปู แบบของภาษาท่ใี ชอ ยใู นเครอ่ื ง

บทที่ 8 Streams I/O 205เร่ิมตนกบั Javaเราจะมาดตู วั อยา งทเี่ กยี่ วของกับไฟล ในหลาย ๆ รูปแบบเพอ่ื ทาํ ใหเกิดความเขา ใจถงึ วธิ ีการ และกระบวนการตาง ๆ ทเี่ ก่ียวของกบั input และ output เราจะเร่ิมตนดว ยการตรวจสอบขอมูลตาง ๆ ที่เกี่ยวกบั ไฟล จากโปรแกรม FileInfo.java//FileInfo.javaimport java.io.*;class FileInfo { public static void main(String[] args) { //get path from command-line argument File path = new File(args[0]); //display some info. about this file if(path.exists()) { System.out.println(path + \" does exist.\"); System.out.println(\"Readable : \" + statusOk(path.canRead())); System.out.println(\"Writable : \" + statusOk(path.canWrite())); System.out.println(\"Directory? : \" + statusOk(path.isDirectory())); System.out.println(\"File? :\"+ statusOk(path.isFile())); System.out.println(\"Hidden? : \" + statusOk(path.isHidden())); } else { System.out.println(path + \" does not exist.\"); }} //return \"Yes\" or \"No\" public static String statusOk(boolean yes) { return yes ? \"Yes\" : \"No\"; }}โปรแกรมเรม่ิ ตน ดว ยการสรา ง object path จาก class File ดวยขอมลู ทีม่ าจาก command-lineargument ซึ่งอยูใ นรูปแบบe:\bc221Book\sourcee:\bc221Book\source\source\bc221Book\source\FileInfo.javaตัวอยางสองตวั แรกอยูในรปู แบบท่เี รยี กวา absolute path สวนสองตัวสดุ ทา ยอยูในรปู แบที่เรยี กวาrelative pathabsolute path เปนการกําหนดท่ีมาท่ไี ปดว ยตวั อกั ษรของ drive สว น relative path จะไมมีการกาํ หนดตวั อกั ษรของ drive แตการทาํ งานท้ังหมดจะอยูภายใน directory นนั้ ๆ ดังตวั อยา งผลลัพธข องการ runนี้>java FileInfo \bc221Book\bc221Book does exist.Readable : YesWritable : Yes ภาควิชาคอมพิวเตอรธ รุ กจิ วทิ ยาลัยฟารอ สี เทอรน

บทท่ี 8 Streams I/O 206เริม่ ตนกับ JavaDirectory? : YesFile? : NoHidden? : No>java FileInfo \bc221Book\source\FileInfo.java\bc221Book\source\FileInfo.java does exist.Readable : YesWritable : YesDirectory? : NoFile? : YesHidden? : No>java FileInfo \bc221Book\FileInfo.java\bc221Book\FileInfo.java does not exist.ผลลัพธข องการ run ท้ังสามคร้ังใช relative path เปนตัวกําหนดการคนหา directory และ file สวนผลลพั ธด านลา งนี้เปนการาคน หาจาก absolute pathE:\bc221Book\source>java FileInfo e:\bc221Book\source\FileInfo.javae:\bc221Book\source\FileInfo.java does exist.Readable : YesWritable : YesDirectory? : NoFile? : YesHidden? : Noเราเรยี กใช method ทม่ี ีอยูใ น class File ในการตรวจสอบขอมูลของ file วา เปน file ลกั ษณะไหน ขอ มลูเฉพาะคอื อะไร คาํ วา file ใน Java นน้ั เปนไดส องอยาง คือ file ทีเ่ กบ็ ขอมูลที่เราใช (หรอื ระบบใช) และfile ทเ่ี กบ็ file หรอื ทร่ี ยี กวา directory (หรอื folder)Java ยงั มี method ที่ใชใ นการตรวจสอบขอมูลของ file อกี หลายตัว เราจะลองใช method เหลา นใ้ี นโปรแกรมตัวอยา งตอไปน้ี//FileInfo1.javaimport java.io.*;import java.util.Date;class FileInfo1 { public static void main(String[] args) { //explain how to use if no argument is given if(args.length < 1) { System.out.println(\"Usage: FileInfo1 file-name\"); System.exit(1); } //display information about this file echoFileInfo(new File(args[0])); }private static void echoFileInfo(File file) { //display if file is a file or a directory if(file.isFile()) System.out.println(\"\n\" + file + \" is a file.\"); if(file.isDirectory()) { String []list = file.list(); System.out.println(\"\n\" + file + \" is a directory.\"); System.out.println(\"There are \" + list.length + \" items in this directory.\"); ภาควิชาคอมพิวเตอรธุรกจิ วทิ ยาลัยฟารอ สี เทอรน

บทท่ี 8 Streams I/O 207เร่ิมตนกับ Java } //lastModifeid() returns amount of milliseconds the file //was last modified, e.g. 1045375241775 since //January 1, 1970, 00:00:00 GMT. We have to create a date //object from this data. long lastModified = file.lastModified(); Date dateModified = new Date(lastModified); //display information about this file System.out.println( \"Absolute path: \" + file.getAbsolutePath() + \"\n Name: \" + file.getName() + \"\n Parent: \" + file.getParent() + \"\n Path: \" + file.getPath() + \"\n Length: \" + file.length() + \"\n Last modified: \" + dateModified); }}โปรแกรม FileInfo1.java เรยี กใช method 5 ตัวในการแสดงขอ มูลของไฟลท ก่ี ําหนดให (ผานทางcommand-line argument) ซ่งึ เปนการเรียกใชโดยตรง และไมมีความยงุ ยากในการเรยี กใช มี methodเพยี งตวั เดยี วเทา นั้นทีเ่ ราตองปรับปรงุ ผลลพั ธท ่ี method ตัวนสี้ งมาให method ทว่ี านีค้ อื lastModified()lastModified() จะสง คา ที่มีชนดิ เปน long ทเ่ี ปน คาของ วันและเวลาท่ไี ฟลไดร บั การเปลย่ี นแปลงครง้ัสดุ ทายในรปู แบบของ millisecond เชน 1045375241775 ซ่งึ เราไมสามารถบอกไดว าเปน วนั ทเ่ี ทา ไรเวลาอะไร เราตอ งใชคา นใ้ี นการสรา ง วันขึน้ ใหมผานทาง class Date ดังน้ีlong lastModified = file.lastModified();Date dateModified = new Date(lastModified);หลงั จากนน้ั เราก็แสดงผลออกทางหนา จอ ดงั ที่แสดงใหด ูเปน ตัวอยางดานลางน้ี>java FileInfo1 e:\bc221Book\sourcee:\bc221Book\source is a directory.There are 328 items in this directory.Absolute path: e:\bc221Book\source Name: source Parent: e:\bc221Book Path: e:\bc221Book\source Length: 0 Last modified: Wed Feb 26 07:47:48 GMT+07:00 2003>java FileInfo1 FileInfo1.javaFileInfo1.java is a file.Absolute path: E:\b221Book\source\FileInfo1.java Name: FileInfo1.java Parent: null Path: FileInfo1.java Length: 1236 Last modified: Tue Feb 25 14:06:13 GMT+07:00 2003>java FileInfo1Usage: FileInfo1 file-nameตวั อยางตอไปเปน โปรแกรมทแ่ี สดงรายละเอยี ดของ directory วา ประกอบไปดวยไฟล หรอื sub-directory อะไรบา ง ภาควิชาคอมพิวเตอรธ ุรกิจ วทิ ยาลยั ฟารอ ีสเทอรน

บทท่ี 8 Streams I/O 208เริม่ ตนกบั Java//DirListing.java//adopted from Bruce Eckel'simport java.io.*;import java.util.Arrays;//extract file name from path//must implements FilenameFilter and override method accept()//to get files with given information into a listclass DirFilter implements FilenameFilter { String fileName;//constructorDirFilter(String fileName) { this.fileName = fileName;} //this method is called by method list() from class File //to include a file if it contains a given info public boolean accept(File path, String name) { //get only file name String file = new File(name).getName(); //if in fact the file exists we will get the first index //of this file, which causes accept() to return true, //otherwise we will get -1 and returns false return file.indexOf(fileName) != -1; }}class DirListing { public static void main(String[] args) { //create file object with a default directory File path = new File(\".\"); String[] fileList; //list of files with given criteria//no argument provided, get all files on this directoryif(args.length == 0) fileList = path.list();//information provided, get rid of path and extract files//with given info.else fileList = path.list(new DirFilter(args[0])); Arrays.sort(fileList); //sort the list showDir(fileList); //display the list} //display files to screen public static void showDir(String[] list) { for(int i = 0; i < list.length; i++) System.out.println(list[i]); }}กอ นทีจ่ ะอธบิ ายถึงการทํางานของโปรแกรม เรามาดผู ลลัพธ (ตดั ทอนบางสว นออก) กันกอ น>java DirListing java ภาควิชาคอมพิวเตอรธุรกจิ วทิ ยาลัยฟารอสี เทอรน

บทที่ 8 Streams I/O 209เร่ิมตนกับ JavaAccess.javaAccount.javaAdd1To100.java … …AddNumbers2.javaThrowsWithTry.javaThrowsWithTry1.javaTriangle.javaTryAndCatchExample1.javaTryAndCatchExample2.javaTwo.javaUpperLower.javaUpperLower2.javaVariables.javaVowels.javaZeroDivideException.javap.java>java DirListing teBankRate.classBankRate.javaByteShort.classByteShort.javaCalculate.classCalculate.javaโปรแกรม DirListing.java จะแสดงรายการของขอมูลทอ่ี ยูใน directory นน้ั ๆ ตามขอกําหนดท่ีเราต้ังใหเชนถาเราตอ งการแสดงไฟลท ัง้ หมดท่ีมีอยูเราก็ใชค าํ ส่ัง DirListing โดยไมมกี ารกําหนดใด ๆ แตถาตอ งการแสดงผลดว ยขอ กําหนด เชน ตอ งการแสดงไฟลท กุ ตัวท่ีมคี ําวา \"te\" อยใู นไฟลเ ราก็ใชคาํ สั่งDirListing te เปนตนโปรแกรมของเราตอ งเรยี กใช interface FileNameFilter เพอ่ื ทาํ การ override method accept() ทที่ าํหนา ทใ่ี นการกรองขอมูลสาํ หรบั ให method list() ท่อี ยูใ น class File ใช โดยกําหนดให methodaccept() ตรวจสอบไฟลจ าก path เฉพาะไฟลทถ่ี ูกตองตามเงอื่ นไขทีก่ ําหนดไวแ ลว จึงบอก methodlist() วา ไฟลต วั น้คี วรเกบ็ ไวใน list ประโยคทแ่ี สดงผลโดยไมต อ งกําหนดเงื่อนไข ตองตรวจสอบกบัargs.length ถาคา น้ีเปน 0 เราจะเก็บไฟลท กุ ตัวไวใน array list ดวยการเรียกใชfileList = path.list();แตถ า มกี ารกําหนดเง่อื นไข เราจะสงเงื่อนไขนไี้ ปให method accept() เพอื่ ทาํ การคัดเลือกไฟลทถ่ี ูกตอ งตามเง่อื นไข ดว ยประโยคfileList = path.list(new DirFilter(args[0]));สมมตวิ า args[0] ของเรามคี า เปน \"te\" (ดงั ตวั อยา ง) \"te\" ก็จะถูกเก็บไวเ ปน ตวั ตรวจสอบวา ไฟลท ี่อยูในpath มีคําน้อี ยหู รือไม เชน ไฟลช ่ือ Calculate.javaMethod list() กาํ หนดให parameter ทส่ี งเขา ไปเปน object จาก class FileNameFilter ดงั น้ันเราสามารถทจ่ี ะเขยี น method accept() ในลกั ษณะใดก็ได ในที่นเี้ ราดึงเอาเฉพาะชอ่ื ไฟลท ไี่ มม ี pathรวมอยดู ว ย ดว ยการกําหนดดงั นี้String file = new File(name).getName(); ภาควิชาคอมพิวเตอรธุรกิจ วทิ ยาลัยฟารอีสเทอรน

บทที่ 8 Streams I/O 210เรมิ่ ตนกับ Javaหลงั จากนัน้ เราใช method indexOf() จาก class String ในการตรวจสอบวา \"te\" มีอยูใ นไฟลน้หี รือไมซึ่งถามคี าที่ไดจ าก indexOf() จะเปน ตาํ แหนง ท่ี \"te\" อยู แตถาไมม ไี ดคา -1 เรานําคา น้มี าเปรยี บเทยี บกบั -1 เพอ่ื บอกให list() รูวา ควรเกบ็ ไฟลต ัวน้หี รอื ไม (true = เก็บ false = ไมเ กบ็ )return file.indexOf(fileName) != -1;ไฟลท กุ ตวั ท่เี ราไดจาก method list() จะถกู เก็บไวใ นตัวแปร fileList เพอ่ื เอาไวใ ชใ นการแสดงผลตอ ไปแตกอนที่เราจะแสดงผล เราทาํ การเรยี งลําดบั ของไฟลใน fileList ดว ยการเรยี กใช method sort() ของclass Arraysโปรแกรมตวั นี้อาจดูเขา ใจยากสักหนอ ย แตก ไ็ มย ากเกินไปนัก ผูอานตองทาํ ความเขา ใจในเรื่องของการเรยี กใช method list() ท่มี าจาก class File รวมไปถึงการเขยี น code ตามขอกําหนดท่เี ราตอ งการในmethod accept() ส่งิ ทเ่ี ราตอ งคํานึงถงึ คือMethod list() ใน class File มอี ยสู องตวั คอื ตวั ทีไ่ มมี parameter และตัวท่ีมี parameter สําหรบัmethod ตัวทม่ี ี parameter นี้ parameter ตอ งเปน object จาก class FileNameFilter ดงั นน้ั เราตองสรา ง class ทีม่ าจาก class น้ีพรอ มทงั้ ทําการ override method accept() ใหทาํ งานตามท่ีเราตองการผอู านควรทดลอง run โปรแกรมตัวนด้ี วยเง่อื นไขตาง ๆ เพื่อใหเ กดิ ความเขาใจมากยงิ่ ขนึ้ และควรทดลองเขยี น code ให method accept() ใหมโ ดยกาํ หนดใหทาํ การตา ง ๆ ทตี่ า งออกไปจากทีเ่ ขียนในโปรแกรมตัวอยา งน้ีเราไดพดู ถึงการแสดงรายการของไฟลท ม่ี ีอยใู น directory การสรางเงื่อนไขใหก บั list() และ accept()พอสมควรแลว ตอ ไปเราจะพูดถงึ การอาน การเขียน ไฟล โดยเราจะเรมิ่ ตนท่ี Input streamsInput and Output streams (ชอ งทางการนาํ ขอ มูลเขา และ การนาํ ขอ มลู ออก)Java กาํ หนดใหมกี ารนําขอ มลู เขา สโู ปรแกรมไดห ลายทาง ซ่ึงเรากไ็ ดส มั ผสั ถึงวิธกี ารมาบา งพอสมควรในเรือ่ งของการนาํ ขอ มลู เขาผา นทางชอ งทางการนาํ เขา มาตรฐาน (standard I/O) ตอ ไปนี้เราจะมาดูถึงการนําขอ มลู ทมี่ าจากไฟลเ ขาสูโปรแกรมรูปแบบของขอมูลทถ่ี ูกจัดเกบ็ ในไฟลน ้ันถกู แบง ออกเปนสองลักษณะคือ1. ขอ มลู ที่อยูในรปู แบบของ character เชน code ของโปรแกรมทสี่ รา งขึน้ จาก Text editor พดู งา ย ๆ ก็คือ เราสามารถทจ่ี ะอานขอมลู เหลานไ้ี ด เราเรยี กไฟลแ บบน้วี า text file2. ขอมลู ทีถ่ กู จดั เกบ็ ในรูปแบบของ binary data เชน ขอ มูลทถ่ี กู เกบ็ ในรปู แบบของ MS Word เรา ไมสามรถทจ่ี ะอา นขอมลู เหลานไี้ ดตอ งอาศัยโปรแกรมในการชวยอา น เราเรยี กไฟลในรูปแบบนี้ วา binary fileเราจะเร่มิ ดวยการอานขอมูลจาก text file ท่ีเก็บ code ของโปรแกรมที่เราไดเ ขยี นข้นึ//ReadingTextFile.javaimport java.io.*;class ReadingTextFile {//don't want to deal with error, let Java takes care of itpublic static void main(String[] args) throws IOException {BufferedReader in;//input bufferFileReader file; //input fileString str; //string to store characters read from filefile = new FileReader(args[0]); //open an input filein = new BufferedReader(file); //store contents in bufferint lineNo = 1; ภาควิชาคอมพิวเตอรธรุ กิจ วิทยาลยั ฟารอ สี เทอรน

บทท่ี 8 Streams I/O 211เรมิ่ ตนกับ Java //keep reading from buffer until null is reached while((str = in.readLine()) != null) { System.out.println(lineNo + \" \" + str); lineNo++; } in.close(); //manually close the file }}เราเปดไฟลท ี่ตอ งการอา นดวย FileReader() พรอ มกับการเรยี กใช BufferedReader() เพ่ือใหการอานขอมลู ทาํ ไดร วดเรว็ ข้ึน เราอานขอมลู เขา มาเกบ็ ไวใ น str ทลี ะหนึง่ แถวจนกวาขอมูลหมดจาก bufferหลังจากนน้ั เรากส็ งขอ มูลทอ่ี า นไดอ อกไปยงั หนา จอพรอมทง้ั เลขที่บรรทดั เม่อื สง ขอ มลู หมดแลวเรากป็ ดไฟลด วยการใช close() ผลลพั ธทเี่ ราไดจ ากการสงไฟล ReadingTextFile.java ไปใหโ ปรแกรมนี้ คือ1 //ReadingTextFile.java23 import java.io.*;45 class ReadingTextFile {6 //don't want to deal with error, let Java takes care of it7 public static void main(String[] args) throws IOException {8 BufferedReader in; //input buffer9 FileReader file; //input file10 String str; //string to store characters readfrom file1112 file = new FileReader(args[0]); //open an input file13 in = new BufferedReader(file); //store contents inbuffer1415 int lineNo = 1;16 //keep reading from buffer until null is reached17 while((str = in.readLine()) != null) {18 System.out.println(lineNo + \" \" + str);19 lineNo++;20 }21 in.close(); //manually close the file22 }23 }เรามาดตู ัวอยา งที่อา นขอมูลดว ยการใช FileInputStream() และ read() ในการอานกันบา ง//ReadTextFile.javaimport java.io.*;class ReadTextFile { public static void main(String[] args) throws IOException { FileInputStream in; //file input stream int ch; //store each character read try { in = new FileInputStream(args[0]); while((ch = in.read()) != -1) { System.out.print((char)ch); } in.close(); } ภาควิชาคอมพิวเตอรธรุ กจิ วทิ ยาลยั ฟารอ ีสเทอรน

บทที่ 8 Streams I/O 212เร่ิมตนกบั Java //file not found catch(FileNotFoundException e) { System.err.println(\"Cannot find: \" + args[0]); System.exit(1); } //no argument specified catch(ArrayIndexOutOfBoundsException e) { System.err.println(\"Usage: ReadTextFile file-name\"); System.exit(1); } }}โปรแกรมตวั นใี้ ช FileInputStream() เปน ตัวเปด ไฟล และใช read() ในการอานขอมูลทีละ byte จากFileInputStream ทําการจดั เก็บขอมูลทอ่ี านไดไวใน ch พรอ มทัง้ สงขอมูลท่อี านไดน ีอ้ อกไปทางหนาจอจนกวา การอานจะสิ้นสุดลง โดยอานเจอ -1 หรือ EOF (End Of File)ในการสงขอ มลู ทอี่ า นไดออกไปยังหนา จอนน้ั เราตองทาํ การ cast ใหก บั ch กอนมิเชนน้นั แลวขอมลู ที่สงออกไปจะไมตรงกับที่อานเขามา โปรแกรมของเรายังไดท าํ การตรวจจบั error ทอ่ี าจเกดิ ขึน้ สองตวั คอืโปรแกรมหาไฟลไ มเ จอ และ ผใู ชไมก าํ หนดชอ่ื ไฟลท ใ่ี ชเ ปน ขอ มลู สําหรับการเปดอานหลังจากทดลอง run ดว ยไฟล ReadTextFile.java ผลลัพธท ไ่ี ดคือ//ReadTextFile.javaimport java.io.*;class ReadTextFile {public static void main(String[] args) throws IOException { FileInputStream in; //file input stream int ch; //store each character read try { in = new FileInputStream(args[0]); while((ch = in.read()) != -1) { System.out.print((char)ch); } in.close(); } //file not found catch(FileNotFoundException e) { System.err.println(\"Cannot find: \" + args[0]); System.exit(1); } //no argument specified catch(ArrayIndexOutOfBoundsException e) { System.err.println(\"Usage: ReadTextFile file-name\"); System.exit(1); } }}character streams โดยท่วั ไปเหมาะสมกับการอา น และเขยี นขอมลู ท่เี ปน text ดังนนั้ หากจะเอามาใชกบัขอมูลอื่น ๆ กจ็ ะสรา งความยงุ ยากในการอานและเขียนมากพอสมควร ดังนน้ั ในการอานและเขยี นขอมูลท่ีไมใช text เราจงึ ตอ งใชการอา นและเขียนขอ มูลทีอ่ ยใู นรูปแบบของ binary data แตก อ นที่จะพดู ถึงเร่อื งของ Binary file เราจะมาดูกันถงึ ความยุง ยากท่ีวา ในการทาํ งานกบั text file ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลัยฟารอ ีสเทอรน

บทท่ี 8 Streams I/O 213เรมิ่ ตน กบั Javaโปรแกรม TextWithStreamTok.java อานขอ มูลที่ถกู เกบ็ ไวในรปู แบบของ text นาํ มาประมวลผล เสรจ็แลวจงึ สงขอ มลู กลับไปยังหนา จอ เพือ่ ใหผอู า นเขาใจงา ยขน้ึ เราจงึ จดั เกบ็ ขอ มูลอยใู น formatString double intเชนNotebook 12.00 30CoffeeMug 5.00 40PaperCutter 12.50 25และเราจะกาํ หนดใหม ีขอ มลู เพียง 3 ตัวเทา นั้น ลองมาดูการใช StreamTokenizer ท่ีเราไดพดู ถงึ ตอนที่เราอา นขอมลู นาํ เขา จาก keyboard กอนหนา น้ี วา จะนํามาใชกบั ขอ มลู ท่อี ยูในไฟลไดอ ยา งไร ในโปรแกรมตวั อยา งดานลา งนี้//TextWithStreamTok.java - Reading text data from a fileimport java.io.*;class TextWithStreamTok { public static void main(String[] args) throws IOException { BufferedReader in = null; //input buffer FileReader file = null; //input file StreamTokenizer stream = null; //tokens try { file = new FileReader(args[0]); //get a file fromargument-list in = new BufferedReader(file); //storage buffer //create tokens stream = new StreamTokenizer(in); stream.eolIsSignificant(true); //EOL counted but ignored } catch(FileNotFoundException e) { System.err.println(\"Cannot find file: \" + args[0]); System.exit(1); } //arrays to store data only 3 items as example e.g. //description prices unit //Coffee-Mug 12.5 30 String[] descs = new String[3]; double[] prices = new double[3]; int[] units = new int[3]; int i = 0, j = 0, k = 0; //arrays' indices boolean first = true; //make sure correct data is read try { //reading tokens into corresponding arrays //until EOF is reached while(stream.nextToken() != StreamTokenizer.TT_EOF) { //data is a string if(stream.ttype == StreamTokenizer.TT_WORD) { descs[i++] = stream.sval; } //data is a number (price or unit) if(stream.ttype == StreamTokenizer.TT_NUMBER) { //first data in line is price ภาควิชาคอมพิวเตอรธุรกจิ วิทยาลัยฟารอ สี เทอรน

บทท่ี 8 Streams I/O 214เรมิ่ ตนกับ Java if(first == true) { prices[j++] = stream.nval; first = false; } //next one is unit price else { units[k++] = (int)stream.nval; first = true; } } //ignore EOL if(stream.ttype == StreamTokenizer.TT_EOL) { /* do nothing */ } } in.close(); //close the stream } //trouble reading file catch(IOException e) { System.err.println(\"Error reading file.\"); e.printStackTrace(); System.exit(1); } //too many items for arrays catch(ArrayIndexOutOfBoundsException e) { System.err.println(\"Array index out of bound.\"); e.printStackTrace(); System.exit(1); } display(descs, prices, units); //display data } //display data to screen private static void display(String[] d, double[] p, int[] u) { double total = 0.00; for(int i = 0; i < d.length; i++) { total = p[i] * u[i]; System.out.print(d[i] + \"\t\" + p[i]); System.out.println(\"\t\" + u[i] + \"\t\" + total); } }}การทํางานหลกั ๆ ของโปรแกรมก็คือ การอา นขอ มลู ทถ่ี กู จดั เก็บใน format ทไ่ี ดก ลา วไว สง่ิ สาํ คัญทเ่ี ราตองคาํ นงึ ถงึ คอื ตําแหนงและชนดิ ของขอมลู ทีเ่ ราตอ งอา น กอนอืน่ เราตองกาํ หนดชองทางนําเขาขอมูลดังนี้file = new FileReader(args[0]); //get a file from argument-listin = new BufferedReader(file); //storage buffer//create tokensstream = new StreamTokenizer(in);stream.eolIsSignificant(true); //EOL counted but ignoredหลงั จากนนั้ เรากต็ รวจสอบ token ทเี่ ราอานจาก stream วาเปน ตัวเลขหรือวา เปน stringwhile(stream.nextToken() != StreamTokenizer.TT_EOF) { //data is a string ภาควิชาคอมพิวเตอรธ ุรกิจ วิทยาลัยฟารอ ีสเทอรน

บทที่ 8 Streams I/O 215เริ่มตนกบั Java if(stream.ttype == StreamTokenizer.TT_WORD) { descs[i++] = stream.sval; } //data is a number (price or unit) if(stream.ttype == StreamTokenizer.TT_NUMBER) { //first data in line is price if(first == true) { prices[j++] = stream.nval; first = false; } //next one is unit price else { units[k++] = (int)stream.nval; first = true; } } //ignore EOL if(stream.ttype == StreamTokenizer.TT_EOL) { /* do nothing */ }}เราจะเกบ็ ขอมลู ท่เี ปน string ไวใ น descs[] ขอมลู ทีเ่ ปน double ไวใ น prices[] และขอมลู ท่เี ปน int ไวใน units[] สิ่งท่ีเราตองคํานึงก็คือ ลาํ ดบั ของขอมูลท่เี ปนตวั เลข เรารูว าตัวเลขกลุมแรกทอี่ านไดค อืprices และขอ มลู ถัดไปคือ units ดังนนั้ เราตอ งใชต วั แปร first เปนตัวกาํ หนดท่ีเกบ็ ขอ มลู วา ทีอ่ านไดค รงั้แรกควรไปอยทู ่ี prices[] และที่อา นไดถ ัดมาควรไปอยทู ี่ units[] และเมอ่ื เราอานจนหมดแลว เรากส็ งarrays ท้ังสามตวั ไปให display() ทาํ การประมวลผล และแสดงผลตอ ไปผลลพั ธท ี่เราได จากการ run คือ>java TextWithStreamTok data.datNotebook 12.0 30 360.0CoffeeMug 5.0 40 200.0PaperCutter 12.5 25 312.5ขอมูลทเ่ี กบ็ ไวในไฟล data.dat จะตอ งมชี อ งวางระหวางขอ มูลแตล ะตวั เชนNotebook 12.0 30CoffeeMug 5.0 40PaperCutter 12.5 25หรือจะใหอ ยใู นบรรทัดเดยี วกันก็ได เชนNotebook 12.0 30 CoffeeMug 5.0 40 PaperCutter 12.5 25ทง้ั น้ีเพราะ nextToken() จะอา นขอ มูลที่อยถู ดั จากชอ งวา งไปจนกวา จะเจอชอ งวา งอกี ครัง้ หน่ึงจะเหน็ ไดวา เราตอ งคอยระวังการอานขอมูล เพราะถา ลําดับของการอานขอมูลผดิ โปรแกรมของเราก็จะเกิดความผดิ พลาด และทส่ี ําคญั อีกอยางหนงึ่ คือ ขัน้ ตอนทยี่ งุ ยากของการกําหนดลาํ ดบั ของขอ มลู การอา นขอมลู (ลองนกึ ถงึ การอาน ถาเรามีขอมูลท่เี ปนตวั เลขอยมู ากกวา สองตวั และมีขอมลู ท่ีเปน string อยูระหวา งขอมลู เหลา น)ี้ ดังนนั้ เราจึงไมนยิ มใช text file ในการเก็บขอมูลทเ่ี ปน primitive type เราควรใชtext file ในการทํางานกับขอ มูลท่ีเปน text เทาน้ันตัวอยางตอ ไปเปน การใช StreamTokenizer นับจาํ นวนของคําทมี่ ีอยูใ นไฟล เพอ่ื ท่จี ะแสดงใหเหน็ วาถาขอ มูลเปน text ทงั้ หมดการทาํ งานจะไมมีปญหาเทาไร//WordCount.java - Using StreamTokenizer to count word ภาควิชาคอมพิวเตอรธ รุ กิจ วทิ ยาลยั ฟารอ สี เทอรน

บทท่ี 8 Streams I/O 216เร่มิ ตน กบั Javaimport java.io.*;class WordCount {public static void main(String[] args) throws IOException {//exit if there's no file specifiedif(args.length < 1) { System.out.println(\"Usage: WordCount file-name.\"); System.exit(1);}FileReader inFile = null; //file streamStreamTokenizer stream = null; //tokens streamint count = 0; //number of words in the file try { inFile = new FileReader(args[0]); stream = new StreamTokenizer(inFile); count = wordCount(stream); System.out.println(count + \" words counted in \" + args[0]); } catch(FileNotFoundException e) { System.err.println(\"Cannot find: \" + args[0]); e.printStackTrace(); System.exit(1); } finally { //close the file if(inFile != null) { try { inFile.close(); } catch(IOException e) { /* do nothing */ } } }} //method to count word in the stream private static int wordCount(StreamTokenizer s) throws IOException { int count = 0; try { while(s.nextToken() != StreamTokenizer.TT_EOF) { //count only word if(s.ttype == StreamTokenizer.TT_WORD) count++; } } catch(IOException e) { System.err.println(\"Error reading stream: \" + s); e.printStackTrace(); System.exit(1); } return count; }} ภาควิชาคอมพิวเตอรธ รุ กจิ วทิ ยาลยั ฟารอีสเทอรน

บทที่ 8 Streams I/O 217เร่มิ ตนกับ Javaโปรแกรม WordCount.java ทาํ การนบั จํานวนของคาํ ท่ปี รากฏอยใู นไฟลทมี่ าจาก command-lineargument โดยเรยี กใช StreamTokenizer เปนตัวตรวจสอบวา ขอ มูลทม่ี ีอยูใ นไฟลเปน string หรอื ไมถา เปน กจ็ ะนับ โดยไมส นใจถงึ รูปแบบของ string น้นั ๆ เชน \"s13\" ก็นบั เปน string โปรแกรมWordCount.java ของเราตวั นใี้ ช object จาก FileReader เปนตวั กําหนดชอ งทางผา นไปยังStreamTokenizer โดยตรง ซง่ึ ตางจากตวั อยา งกอนหนานี้ ท่เี ราใช BufferedReader เปน ที่เกบ็ ขอมูลการใช FileReader โดยตรงจะทาํ ใหเ สยี เวลาในการประมวลผลมากถาไฟลม ขี นาดใหญ เพราะฉะนน้ั ถาผูอานตอ งการความเรว็ ในการประมวลผล กต็ อ งใช BufferedReader เปนตวั เก็บขอ มูลทตี่ อ งการประมวลผลเราไดท ดลอง run โปรแกรมดว ยไฟลข อง Windows Xp Æ vbe6.dll ซึ่งมขี นาดเทา กบั 2,498,560bytes ผลลัพธท ไ่ี ดกอ นและหลงั การใช BufferedReader คอื>java WordCount vbe6.dllStart: Fri Feb 28 10:08:52 GMT+07:00 2003279829 words counted in vbe6.dllStop: Fri Feb 28 10:08:54 GMT+07:00 2003>java WordCount vbe6.dllStart: Fri Feb 28 10:10:35 GMT+07:00 2003279829 words counted in vbe6.dllStop: Fri Feb 28 10:10:36 GMT+07:00 2003จะเหน็ วา การประมวลผลดวยการใช BufferedReader ใชเ วลานอ ยกวา การใช FileReader โดยตรง (ดีข้ึนประมาณ 1 วนิ าท)ี เราใชการวดั หาเวลาอยา งงา ย ๆ ดวยการใช Date เปน ตวั บอกถึงความแตกตางกอนและหลังการอานขอมลู ในไฟล โดยเปล่ียนแปลง code บางสว นดังนี้ … //buffer holding dataBufferedReader buf = null; …try { System.out.println(\"Start: \" + new Date()); inFile = new FileReader(args[0]); buf = new BufferedReader(inFile); stream = new StreamTokenizer(buf); … … …finally { //close the file if(inFile != null) { try { inFile.close(); } catch(IOException e) { /* do nothing */ } } //close stream if(buf != null) { try { buf.close(); System.out.println(\"Stop: \" + new Date()); } catch(IOException e) { /* do nothing */ } }…… ภาควิชาคอมพิวเตอรธ รุ กจิ วิทยาลยั ฟารอีสเทอรน

บทท่ี 8 Streams I/O 218เร่มิ ตนกับ Javaอีกสงิ่ หน่ึงทเี่ ราไดพดู ถงึ กอนหนาน้ี แตไมเคยไดใชเ ลยกค็ ือ finally เพือ่ แสดงใหด ูถงึ ประโยชนข องfinally เราจงึ ใช finally เปน ตัวปด ไฟลใ นโปรแกรมใหเ รา ผอู านควรใช finally เปนตัวปด ไฟลเ สมอ(โปรแกรมตวั อยา งในบทนหี้ ลาย ๆ ตวั อาจไมใช finally เปน ตวั ปด ไฟล แตน นั่ ไมไ ดหมายความวา ผอู า นจะใชไมไ ด)ถาผอู านตอ งการทจ่ี ะจบั เวลาการทาํ งานของโปรแกรม หรือสวนของโปรแกรม Java มี method อกี ตัวหนงึ่ ทผี่ อู านสามารถเรยี กใชไ ดน น่ั ก็คือ method currentTimeMillis() ดงั ตัวอยางการใชท แ่ี สดงไวดานลา งน้ี//ElapsedTime.javaclass ElapsedTime { public static void main(String[] args) { long startTime, stopTime; //get starting time startTime = System.currentTimeMillis(); //do some looping for(int i = 0; i < 100000; i++) for(int j = 0; j < 100000; j++) ; //get ending time stopTime = System.currentTimeMillis(); //calculate elapsed time double elapsedTime = (double)(stopTime - startTime) / 1000.0; System.out.print(\"Elapsed time: \"); System.out.println(elapsedTime + \" seconds.\"); }}ผลลัพธท ่ีไดจ ากการ run คือElapsed time: 85.093 seconds.โปรแกรม ElapsedTime.java เรียกใช currentTimeMillis() กอนและหลงั จากการใช loop หลังจากน้นั ก็หาเวลาทใี่ ชไ ปดวยการนําเอาเวลาเรมิ่ ตนไปลบออกจากเวลาที่ไดหลังจากการใช loopเราสามารถทจี่ ะทําใหการทาํ งานกบั ขอ มูลทีเ่ ปน text ไดงา ยขึ้นถา เรากําหนดใหม ี ตวั แบงขอ มลู(delimiter) ระหวา งขอ มูลแตล ะตัวทอี่ ยใู นไฟล ซึ่งตัวแบง ทวี่ าน้ีจะเปนตวั อกั ษรใด ๆ กไ็ ดท ี่ไมมสี ว นเกี่ยวขอ งกบั ขอมลู ท่ีอยใู นไฟล เชน เราอาจใชเ ครอ่ื งหมาย \"|\" เปนตวั แบง ขอ มูลในไฟลต วั อยางทไ่ี ดพ ดูถึงกอ นหนา น้ี ลองมาดูตวั อยา งการใชต วั แบง ที่วา นีก้ นั//TokenWithDelimiter.java - Using '|' as delimiter in a text fileimport java.io.*;import java.util.StringTokenizer;import java.lang.Integer;class TokenWithDelimiter { public static void main(String[] args) throws IOException { //data to write to file String[] items = {\"Notebook\", \"Coffee Mug\", \"Paper cutter\"}; double[] prices = {12.0D, 5.0D, 12.5D}; ภาควิชาคอมพิวเตอรธุรกจิ วทิ ยาลัยฟารอ สี เทอรน

บทที่ 8 Streams I/O 219เรมิ่ ตน กับ Javaint[] units = {30, 40, 25}; //check to see if a file is provided if(args.length < 1) { System.err.println(\"Usage: TokenWithDelimeter file-name.\"); System.exit(1); } writeToFile(args[0], items, prices, units); processData(args[0]); }//writing data in arrays to a given fileprivate static void writeToFile(String fileName, String[] items, double[] prices, int[] units) throws IOException { File dataFile = null; FileWriter fWriter = null; BufferedWriter buffer = null; PrintWriter out = null;try { dataFile = new File(fileName); fWriter = new FileWriter(dataFile); buffer = new BufferedWriter(fWriter); out = new PrintWriter(buffer); //printing data to file with '|' in between for(int i = 0; i < items.length; i++) { out.print(items[i]); out.print('|'); out.print(prices[i]); out.print('|'); out.println(units[i]); } } catch(IOException e) { System.err.println(\"Error writing to file\"); e.printStackTrace(); System.exit(1); } finally { if(out != null) out.close(); }}//reading data from a given file & display to screenprivate static void processData(String fileName) throws IOException {String item; //item readdouble price; //price readint unit; //unit readFile dataFile = null;FileReader fReader = null;BufferedReader buffer = null;String input = null;try { ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลยั ฟารอสี เทอรน

บทที่ 8 Streams I/O 220เริ่มตนกบั Java dataFile = new File(fileName); fReader = new FileReader(dataFile); buffer = new BufferedReader(fReader); input = buffer.readLine(); //read first line of data //keep reading until there's no more lines to read while(input != null) { //get token from input-line - skip '|' StringTokenizer token = new StringTokenizer(input, \"|\"); item = token.nextToken(); price = Double.parseDouble(token.nextToken()); unit = Integer.parseInt(token.nextToken()); //display to screen System.out.print(item + \"\t\" + price + \"\t\" + unit); System.out.println(\"\t\" + price * unit); input = buffer.readLine(); } } catch(IOException e) { System.err.println(\"Error reading file\"); e.printStackTrace(); System.exit(1); } finally { if(buffer != null) buffer.close(); } }}เราใชเครื่องหมาย '|' ในการแบง ขอ มูลทีอ่ ยใู นไฟล พรอมทง้ั ใช class StringTokenizer เปน ตัวดึงขอ มลูที่อา นมาจากไฟล หลังจากทเ่ี ราเขยี นขอ มลู ทอ่ี ยใู น arrays ทงั้ สามตวั ไปเก็บไวใ นไฟลด ว ยการใช print()และ println() ผอู านควรสังเกตถึงการเขียนขอ มลู ในแตล ะครง้ั วา เราเขยี น '|' ตามหลังเสมอ ยกเวน การเขียนขอ มลู ตัวสดุ ทา ยdataFile = new File(fileName);fWriter = new FileWriter(dataFile);buffer = new BufferedWriter(fWriter);out = new PrintWriter(buffer);//printing data to file with '|' in betweenfor(int i = 0; i < items.length; i++) { out.print(items[i]); out.print('|'); out.print(prices[i]); out.print('|'); out.println(units[i]);}หลงั จากนัน้ เรากอ็ านขอมูลกลบั ออกมาดว ย readLine() เราทําการดงึ ขอ มลู แตล ะตัวทถี่ กู แบง ดว ย '|' ดวยการใช nextToken() แตก อ นทเี่ ราจะทาํ การดงึ ขอ มลู ทกุ ครงั้ ในแตล ะบรรทดั เราจะตอ งกําหนดเงือ่ นไขใหtoken ของเราเสยี กอน ดว ยการใชStringTokenizer token = new StringTokenizer(input, \"|\");เพอื่ ทจี่ ะบงั คับใหก ารดึงขอมลู น้นั เกดิ ขึน้ ระหวางเคร่ืองหมาย '|' ขอมลู ตัวแรกท่ีเราดึงออกมาเปน Stringเราจงึ ไมตองแปลงขอมูลตัวนี้ แตข อมูลอกี สองตวั ทเ่ี ราดึงออกเปน double และ int ทถ่ี กู เก็บใหเ ปน ภาควิชาคอมพิวเตอรธรุ กจิ วทิ ยาลัยฟารอีสเทอรน

บทท่ี 8 Streams I/O 221เร่ิมตนกับ JavaString ในการเขียน ดังน้นั เราจึงตองแปลงขอ มูลทั้งสองตัวน้ี หลงั จากทเ่ี ราไดข อมูลทงั้ สามตัวแลว เราก็แสดงผลออกไปยังหนา จอdataFile = new File(fileName);fReader = new FileReader(dataFile);buffer = new BufferedReader(fReader);input = buffer.readLine(); //read first line of data//keep reading until there's no more lines to readwhile(input != null) { //get token from input-line - skip '|' StringTokenizer token = new StringTokenizer(input, \"|\"); item = token.nextToken(); price = Double.parseDouble(token.nextToken()); unit = Integer.parseInt(token.nextToken()); //display to screen System.out.print(item + \"\t\" + price + \"\t\" + unit); System.out.println(\"\t\" + price * unit); input = buffer.readLine();}ในการเขยี นไฟลของเราครง้ั นเี้ ราใช PrintWriter เปนตวั ชวย ซง่ึ ภายใน class PrintWriter นีเ้ ราสามารถที่จะเรยี กใช print() และ println() ได ทําใหก ารเขียนขอ มูลสง ไปยงั ไฟลของเราเหมอื นกบั การเขยี นทเี่ ราไดทํามากอนหนา นต้ี อนทเ่ี ราสง ขอมูลไปยังหนา จอ แตเราจะตอ งใช PrintWriter รว มกับ FileWriterเพอ่ื ใหก ารเขยี นไปยงั ไฟลท าํ ได และ BufferedWriter เพอื่ ใหท าํ ไดอ ยา งมปี ระสิทธภิ าพ (การใช bufferจะชว ยใหการทาํ งานกับขอมลู ไวขึน้ )ผลลัพธท ไ่ี ดจ ากการ run>java TokenWithDelimiter tokens.datNotebook 12.0 30 360.0Coffee Mug 5.0 40 200.0Paper cutter 12.5 25 312.5Binary fileในการเขียน binary data เขา สูไฟลน ั้นเราจะตองคํานึงถงึ วธิ กี ารในการท่จี ะเขยี นขอมลู เพราะในการเขยี นขอมลู เขา สูไ ฟลนั้น มีผลตอ การอา นขอ มลู กลบั ออกมา ลําดับของขอ มลู ทเ่ี ขยี นเขา สูไ ฟล จะตอ งอา นกลบัออกมาดว ยขัน้ ตอนเดียวกนัในการเขียนขอ มูลท่ีเปน binary data นนั้ เราสามารถที่จะเลอื กใช method หลาย ๆ ตวั ที่ Java มีใหเปนตัวชวยในการเขยี น เชนMethod Throws ความหมายwriteBoolean(boolean) IOException เขยี นคาของ boolean จํานวน 1 bytewriteShort(int) IOException เขยี นคา ของ short จาํ นวน 2 bytewriteInt(int) IOException เขยี นคาของ int จาํ นวน 4 bytewriteLong(long) IOException เขียนคา ของ long จาํ นวน 8 bytewriteFloat(float) IOException เขยี นคา ของ float จาํ นวน 4 bytewriteDouble(double) IOException เขยี นคา ของ double จาํ นวน 8 bytewriteChar(int) IOException เขียนคาของ char จํานวน 2 bytewriteChars(String) IOException เขียน String จํานวน 2 byte ตอ 1 ตวั อักษรwriteUTF(String) IOException เขยี น String จํานวน 1 byte ตอ ตัวอกั ษร บวกอีก 2 byte สําหรบั คา ของความยาวของ Stringสาํ หรับการอา นน้ัน เราจะใช method น้ี ภาควิชาคอมพิวเตอรธ รุ กิจ วทิ ยาลยั ฟารอ สี เทอรน

บทที่ 8 Streams I/O 222เรม่ิ ตนกับ Java Throws ความหมาย Method EOFException อาน 1 byte สง คา boolean กลับ readBoolean() EOFException อา น 2 byte สง คา Short กลบั readShort() EOFException อา น 4 byte สง คา int กลบั readInt() EOFException อาน 8 byte สง คา long กลบั readLong() EOFException อาน 4 byte สง คา float กลับ readFloat(0 EOFException อาน 8 byte สง คา double กลบั readDouble() EOFException อา น 2 byte สง คา char กลับ readChar() EOFException อา น String UTF readUTF() EOFException ไมอา นขอ มูลจํานวนเทากบั byte ทีก่ ําหนด skipBytes(int)ตวั อยา งตอไปจะเปนตัวอยา งการเขียนขอมูลเขาสไู ฟลในรูปแบบของ binary data หลงั จากนัน้ จะอา นกลับออกมา เราจะเร่มิ ตนดว ยการสราง record จาํ นวน 3 ตัว สรางไฟลส ําหรบั เกบ็ record เหลาน้ี อานrecord ออกมาทลี ะตัว ประมวล พรอมทั้งแสดงผลไปยงั หนา จอRecord คอื กลมุ ขอ มลู ทปี่ ระกอบไปดวยขอ มลู ตาง ๆ ซึ่งอาจเปนขอมลู ชนดิ เดยี วกันหรอื ขอ มูลตางชนดิ กนัก็ได ใน Java เราสราง record ดว ยการใช class เปน ตวั สรา ง เราจะกําหนดให record ของเรามี ขอมลูอยู 3 field เหมอื นกบั ตัวอยางกอ นหนานี้ คือ1. description2. price3. unitเรามาดโู ปรแกรมตวั อยา งกนั ดกี วา//DataFile.java - Sequential Access fileimport java.io.*;class DataFile {public static void main(String[] args) throws IOException {FileOutputStream fout; //file output streamDataOutputStream dout; //data output streamFileInputStream fin; //file input streamDataInputStream din; //data input stream//setting up data to be written to a fileString[] desc = {\"Coffee Mug\", \"Bookmark\", \"Note book\"};double[] prices = {5.00, 2.00, 10.00};int[] unit = {12, 50, 30};//variables storing data read from fileString description;double price, total = 0.00;int unitPrice;//open file for writingtry { fout = new FileOutputStream(args[0]); dout = new DataOutputStream(fout); for(int i = 0; i < desc.length; i++) { dout.writeUTF(desc[i]); dout.writeDouble(prices[i]); dout.writeInt(unit[i]); } dout.close(); ภาควิชาคอมพิวเตอรธรุ กิจ วิทยาลยั ฟารอ ีสเทอรน

บทท่ี 8 Streams I/O 223เรม่ิ ตน กบั Java } catch(FileNotFoundException e) { System.err.println(\"Cannot open \" + args[0]); return; } catch(ArrayIndexOutOfBoundsException e) { System.err.println(\"Usage: DataFile file-name.\"); return; } //open file for input try { fin = new FileInputStream(args[0]); din = new DataInputStream(fin); System.out.println(\"Description\tPrice\tUnit\tTotal\"); while(true) { description = din.readUTF(); price = din.readDouble(); unitPrice = din.readInt(); total = price * unitPrice; display(description, price, unitPrice, total); } } catch(EOFException e) { //use this exception to stop the while loop //and exit the program System.exit(1); } catch(IOException e) { System.err.println(\"Error reading file: \" + e.toString()); System.exit(1); } } //display a record to screen public static void display(String d, double p, int u, double t) { System.out.println(d+\"\t\"+p+\"\t\"+u+\"\t\"+t); }}โปรแกรมของเราใช DataOutputStream และ DataInputStream เปนตวั สง ขอมลู ไปเก็บไวทไ่ี ฟล และเราใช for loop เปน ตวั กําหนดจาํ นวนครง้ั ของการเขยี นfout = new FileOutputStream(args[0]);dout = new DataOutputStream(fout);for(int i = 0; i < desc.length; i++) { dout.writeUTF(desc[i]); dout.writeDouble(prices[i]); dout.writeInt(unit[i]);}หลงั จากนนั้ เรากอ็ านขอ มูลออกมาจากไฟล ตามลําดบั ถาเราลองเปดดูไฟลท ่เี ก็บขอ มูลทเ่ี ราสรางขึ้น เราจะไมสามารถอา นได เพราะขอ มลู เหลา นถี้ กู เกบ็ อยใู นรปู แบบของ binary dataในการอา นขอ มลู ออกมาจากไฟลน ้นั เราใช while loop ในการอา นดวยการกาํ หนดใหเ ปน infinite loopโดยเราจะใช error ทเ่ี กิดขึ้นเปนตวั ยตุ ิการทาํ งานของ loop เนอื่ งจากวา เรารูวา ในการอา นขอมูลออกจากไฟลน น้ั ในท่ีสดุ เรากจ็ ะอา นเจอเคร่อื งหมายทบี่ ง บอกถงึ จดุ จบของไฟล (EOF) ซึ่งอาจเปน การเขียน codeท่ไี มคอยจะสวยเทาไร แตกท็ าํ ใหก ารทาํ งานของโปรแกรมเปน ไปตามทีเ่ ราตอ งการ ภาควิชาคอมพิวเตอรธุรกจิ วทิ ยาลัยฟารอ สี เทอรน

บทที่ 8 Streams I/O 224เร่ิมตนกับ Javafin = new FileInputStream(args[0]);din = new DataInputStream(fin);System.out.println(\"Description\tPrice\tUnit\tTotal\");while(true) { description = din.readUTF(); price = din.readDouble(); unitPrice = din.readInt(); total = price * unitPrice; display(description, price, unitPrice, total);}ผลลัพธท ่ีไดจ ากการ run คอื>java DataFile data.datDescription Price Unit TotalCoffee Mug 5.0 12 60.0Bookmark 2.0 50 100.0Note book 10.0 30 300.0จากผลลัพธท ่ีไดจะเห็นวา การจัดเรียงของขอ มูลทสี่ ง ไปยงั หนาจอ ยงั ดูไมเ รยี บรอ ยและสวยงามเทาไร ถาตองการใหก ารแสดงผลอยใู นรปู แบบทส่ี วยงาม เราจะตอ งสรา ง class ขึน้ มาใชเ องดวยการ extendsclass ท่เี ราสรางขน้ึ จาก class PrintWritter พรอ มกบั ทาํ การสรา ง method output() ทที่ ําการแสดงผลขอมลู ดว ยการจัดเรยี งทางขวา และทําการ override method print() และ println() เราจะสราง classFormatWriter ดังทีแ่ สดงใหด ูในโปรแกรมตวั อยางที่ไดดดั แปลงมาจากโปรแกรม DataFile.java//DataFile.java - Sequential Access file//-(modified for formatted output)import java.io.*;//for pretty printing (formatted - right justified)class FormatWriter extends PrintWriter { private int width = 10;//default constructorFormatWriter(Writer output) { super(output);}//constructor with specified widthFormatWriter(Writer out, int width) { super(out); this.width = width;}//set prefer output styleprivate void output(String str) { //calculate spaces int blanks = width - str.length(); //fill with blanks before actual data for(int i = 0; i < blanks; i++) super.print(' '); //print data super.print(str);} ภาควิชาคอมพิวเตอรธรุ กจิ วิทยาลยั ฟารอ ีสเทอรน

บทที่ 8 Streams I/O 225เร่ิมตน กับ Java//our print() and println() methods with different types of datapublic void print(String str) { output(str);}public void println(String str) { output(str); super.println();}public void print(double value) { output(String.valueOf(value));}public void print(int value) { output(String.valueOf(value));} public void println(double value) { this.print(value); super.println(); }}class DataFile {public static void main(String[] args) throws IOException {FileOutputStream fout; //file output streamDataOutputStream dout; //data output streamFileInputStream fin; //file input streamDataInputStream din; //data input stream//setting up data to be written to a fileString[] desc = {\"Coffee Mug\", \"Bookmark\", \"Note book\"};double[] prices = {5.00, 2.00, 10.00};int[] unit = {12, 50, 30};double[] total = new double[3];//open file for writingtry { fout = new FileOutputStream(args[0]); dout = new DataOutputStream(fout); for(int i = 0; i < desc.length; i++) { dout.writeUTF(desc[i]); dout.writeDouble(prices[i]); dout.writeInt(unit[i]); } dout.close();}catch(FileNotFoundException e) { System.err.println(\"Cannot open \" + args[0]); return;}catch(ArrayIndexOutOfBoundsException e) { System.err.println(\"Usage: DataFile file-name.\"); return;}//open file for input//reuse variables desc, prices, and unit//calculate total fro each data item ภาควิชาคอมพิวเตอรธ ุรกจิ วิทยาลัยฟารอีสเทอรน

บทที่ 8 Streams I/O 226เริ่มตนกบั Java try { fin = new FileInputStream(args[0]); din = new DataInputStream(fin); boolean endOfFile = false; //EOF marker int index = 0; //array index while(!endOfFile) { try { //store data in arrays before printing desc[index] = din.readUTF(); prices[index] = din.readDouble(); unit[index] = din.readInt(); total[index] = prices[index] * unit[index]; index++; } catch(EOFException e) { endOfFile = true; //stop while loop din.close(); //close the file } } //display data - right justified display(desc, prices, unit, total); } catch(IOException e) { System.err.println(\"Error reading file: \" + e.toString()); System.exit(1); }} //display a record to screen private static void display(String[] d, double[] p, int[] u, double[] t) { //create object from FileWriter with width of 12 FormatWriter out = new FormatWriter( new BufferedWriter( new FileWriter(FileDescriptor.out)), 12); //display header out.print(\"Description\"); out.print(\"Prices\"); out.print(\"Unit\"); out.println(\"Total\"); //display contents of arrays for(int i = 0; i < d.length; i++) { out.print(d[i]); out.print(p[i]); out.print(u[i]); out.println(t[i]); } out.close(); //close the stream }}เราสรา ง class FormatWriter ขนึ้ มาใหมจาก class PrintWriter พรอมท้ังกาํ หนดใหมี constructor 2โดยท่ตี วั แรกเปน default constructor ทม่ี ีหนาทเี่ รยี ก constructor ของ class PrintWriter สําหรับการกําหนดชอ งทางผา นออกของขอมูล สว นตวั ทสี่ องเรากาํ หนดใหม คี วามกวา งของเนอ้ื ท่ขี องขอ มลู ที่ตองการแสดงFormatWriter(Writer out, int width) { super(out); ภาควิชาคอมพิวเตอรธุรกิจ วิทยาลยั ฟารอสี เทอรน

บทท่ี 8 Streams I/O 227เรมิ่ ตนกับ Java this.width = width;}เราจะใช width ในการกําหนดจาํ นวนของชองวางท่เี ราตองการแสดงกอ นการแสดงขอมลู จริง เชน ถา เรากําหนดให width มีคาเปน 10 และขอ มลู ทต่ี อ งการแสดงมีคา เปน 2 ตวั อกั ษรเราก็จะทาํ การเขยี นชองวา งจาํ นวนเทา กับ 8 ตัว เสรจ็ แลว จึงเขยี นขอ มลู ตามชอ งวา งเหลาน้ี เราทาํ ไดด วยการเขียน methodoutput() ใหท าํ การคาํ นวณหาจํานวนชองวา งท่วี า เมื่อไดแลว จงึ สงไปยังหนา จอดว ยการเรียก print()ของ class PrintWriter หลังจากนัน้ จึงสงขอมลู จริงออกไปMethod output() จะถกู เรียกใชใ น print() และ println() ทเ่ี ราเขยี นข้นึ มารองรบั ขอมลู ตา งชนิดกัน ซ่งึในทีน่ ้เี รามขี อ มลู เพียงสามชนดิ คือ string double และ int การเขยี น print() และ println() กไ็ มย ากดงั น้ีpublic void print(int value) { output(String.valueOf(value));}public void println(double value) { this.print(value); super.println();}เราเพียงแตเรยี ก output() ดว ยคา ท่ีตอ งการแสดงผล แตเ ราจะตอ งเปลย่ี นคา นีใ้ หอ ยูใ นรูปแบบของstring กอนท่ีจะสงคา นีไ้ ปให output()เราเปลย่ี น display() ของเราใหมด วยการรับ parameter ท่ีเปน array แทนทจี่ ะเปนขอมลู เด่ียว ๆ เหมอื นทท่ี าํ กอนหนาน้ี พรอมทั้งประกาศตัวแปรจาก class FormatWriter ท่เี ราเขยี นขนึ้ ดังนี้private static void display(String[] d, double[] p, int[] u, double[] t) { //create object from FileWriter with width of 12 FormatWriter out = new FormatWriter( new BufferedWriter( new FileWriter(FileDescriptor.out)), 12); //display header out.print(\"Description\"); out.print(\"Prices\"); out.print(\"Unit\"); out.println(\"Total\"); //display contents of arrays for(int i = 0; i < d.length; i++) { out.print(d[i]); out.print(p[i]); out.print(u[i]); out.println(t[i]); } out.close(); //close the stream}เพอ่ื ใหก ารสง ขอ มลู ออกทาง standard output เปน ไปได เราตอ งสราง object จากสมาชกิ ทช่ี ื่อ outของ class FileDescriptor (สมาชิกของ FileDescriptor มอี ยสู ามตวั คอื in out และ err ซึง่ หมายถงึชองทางของ input output และ error ตามลําดบั ) หลังจากนนั้ เรากส็ ง object ตัวน้ไี ปใหBufferedWriter เพือ่ สราง buffer สาํ หรับรองรับขอมลู ทจ่ี ะเกดิ ขึน้ และ buffer ตวั นจ้ี ะเปน parameterตวั แรกทถี่ กู สงไปให constructor ของ FormatWriter และ 12 (ซึ่งเปน width) จะถกู สง ไปเปนparameter ตวั ท่สี อง ทาํ ให object out ของเราสามารถใชช อ งทางผา นออกได หลังจากนน้ั เรากแ็ สดงขอมูลดวยการเรียกใช print() และ println() ผาน object ตวั น้ี ภาควิชาคอมพิวเตอรธรุ กจิ วิทยาลัยฟารอีสเทอรน

บทท่ี 8 Streams I/O 228เร่มิ ตนกบั Javaในตัว main() ของเรา เราเปล่ยี นแปลง code ใหทาํ การอา นขอมลู มาเก็บไวใ น array สําหรบั การสงไปแสดงผลใน display() … …boolean endOfFile = false; //EOF markerint index = 0; //array indexwhile(!endOfFile) { try { //store data in arrays before printing desc[index] = din.readUTF(); prices[index] = din.readDouble(); unit[index] = din.readInt(); total[index] = prices[index] * unit[index]; index++; } catch(EOFException e) { endOfFile = true; //stop while loop din.close(); //close the file }}//display data - right justifieddisplay(desc, prices, unit, total); … …เรายังใช EOF error เปนตัวยตุ กิ ารทาํ งานของ loop เหมอื นเดมิ เพยี งแตแ ทนทจ่ี ะใชคา -1 เรากเ็ ลอื กที่จะใชต ัวแปร boolean เปนตวั กาํ หนดการทํางานของ loop แทนผลลัพธท ไี่ ดจ ากการ run คือ>java DataFile data.datDescription Prices Unit Total Coffee Mug 5.0 12.0 60.0 Bookmark 2.0 50.0 Note book 30.0 100.0 10.0 300.0เรายงั สามารถทีจ่ ะทําการแสดงผลท่อี ยใู นรปู แบบทเ่ี ราตอ งการ ไดอ กี หลายรปู แบบ ซึง่ กต็ องขน้ึ อยูกับผเู ขยี นโปรแกรมวา ตองการใหผ ลลัพธอ อกมาในลกั ษณะไหน ผูอา นคงตองใชเ วลาพอสมควรในการศึกษาและทดลองเขยี น code ทท่ี ําใหก ารแสดงผลมคี วามสวยงามมากขึ้นตวั อยา งตอไปนีจ้ ะเปน การแสดงถงึ ความแตกตา งในการใช writeUTF() กบั การใช writeChars()//WriteCharsAndWriteUTF.java - Differences between the to methodsimport java.io.*;class WriteCharsAndWriteUTF { public static void main(String[] args) throws IOException { File f = new File(args[0]); DataOutputStream out = new DataOutputStream( new BufferedOutputStream( new FileOutputStream(f))); out.writeUTF(\"If it does not work, blame the computer.\"); int utfSize = out.size(); ภาควิชาคอมพิวเตอรธ รุ กิจ วทิ ยาลัยฟารอ ีสเทอรน

บทที่ 8 Streams I/O 229เริม่ ตน กับ Java out.writeChars(\"If it does not work, blame the computer.\"); int charsSize = out.size() - utfSize; out.close(); System.out.println(\"writeUTF() writes \" + utfSize + \" bytes.\"); System.out.println(\"writeChars writes \" + charsSize + \" bytes.\"); }}ผลลพั ธท ่ไี ดจ ากการ run คือ>java WriteCharsAndWriteUTF difs.datwriteUTF() writes 42 bytes.writeChars writes 80 bytes.โปรแกรมของเราเขยี น string จาํ นวน 40 ตวั อักษรไปยงั ไฟลดวยการใช writeUTF() และ writeChars()จากผลของการ run จะเห็นวา writeUTF() ใชเ พยี งแค 1 byte ตอตัวอักษรบวกกับอกี 2 byte สําหรบั เกบ็ความยาวของ string สว น writeChars() ใช 2 byte ตอตวั อกั ษรการสรา งและใช Random-access fileตวั อยา งกอ นหนา นเี้ ราเขา หาขอ มูลในไฟลแ บบ กอ น-หลัง หรอื ที่เรยี กวา sequential access ซงึ่ เปนวิธีการทค่ี อนขา งทีจ่ ะใชเ วลามาก ถาขอมูลมอี ยูเปน จํานวนมาก มวี ธิ กี ารอีกวิธีหน่ึงทที่ าํ ใหก ารเขา หา หรือคน หาขอมูลทาํ ไดร วดเร็ว นน่ั กค็ อื การเขาหาแบบทไี่ มตองเขา หาตามลําดับ กอ น-หลงั หรือทเ่ี รยี กวาRandom-accessคําวา random-access ในที่นหี้ มายความวา ขอมลู ที่ถกู ดึงออก หรอื นาํ เขาไมม ีสว นเกี่ยวขอ งกบั ขอ มลู ท่ีถูกดึงออก หรือ นําเขากอนหนา นี้ เชน ในการคน หาเบอรโทรศัพทข องใครสกั คนผานทาง operator ผูคนหา ณ เวลาปจจบุ นั ไมมคี วามเก่ียวของหรอื ความสมั พนั ธใ ด ๆ กับการคน หาทผ่ี า นมากอนหนาในการจดั การกบั ขอ มลู ของ random-access file น้นั จะใชต ัวชีต้ ําแหนง (logical pointer) เปน ตวั กําหนดตาํ แหนงของการนาํ ขอ มูล เขา -ออก ซ่งึ การกําหนดตาํ แหนง จะคาํ นวณจากจดุ เรม่ิ ตนของไฟล (ไมใ ชตําแหนง ท่เี กบ็ จรงิ ในหนว ยความจาํ สํารอง) เราเรียกระยะทางจากจุดเริ่มตน น้วี า offset Java กาํ หนดการเขาหาตาํ แหนง เหลา น้ดี วยการใชค าํ สั่ง seek เพราะฉะน้นั ในการเขา หาขอมลู ถา เรารขู นาดของขอ มลู ท่ีตายตวั (fixed length record) เราก็สามารถเขาหาขอมลู ณ ตําแหนง p ดว ย p * lengthเราจะเริ่มตน ดว ยการสรา ง record ตวั อยาง โดยกาํ หนดให record ของเราประกอบดว ยช่ือ (first name)นามสกุล (last name)ปท ่เี กิด (year of birth)เงินเดือน (salary)เราจะกาํ หนดให record เกดิ จาก class ทมี่ สี มาชกิ ดังทก่ี ลา วขางตน พรอมกับ method ตา ง ๆ ท่ีเกีย่ วของกบั การทํางานกับ record นั้น ๆ//RandomAccessFileDemo.javaimport java.io.RandomAccessFile;import java.io.*;class RandomAccessFileDemo { public static void main(String[] args) throws IOException { //data to be written to a file ภาควิชาคอมพิวเตอรธุรกิจ วทิ ยาลยั ฟารอีสเทอรน

บทท่ี 8 Streams I/O 230เริม่ ตน กับ Java String[] names = {\"John\", \"Paul\", \"Stephen\", \"Hendrix\"}; String[] lasts = {\"Kawakami\", \"Collins\", \"Anderson\", \"McCoy\"}; int[] years = {1965, 1978, 1985, 1972}; double[] pays = {2400.0, 500.0, 5000.0, 9500.0}; //use to randomly select the position in a file //to write to/read from e.g. random[0] is at the second //position, random[2] is at the frist position etc. int []random = {2, 3, 0, 1}; //writing to a file RandomAccessFile f = new RandomAccessFile(\"emp.dat\", \"rw\"); try { for(int i = 0; i < 4; i++) { Employee emp = new Employee(names[i], lasts[i], years[i], pays[i]); emp.write(f, random[i]); } } catch(IOException e) { System.err.println(\"Error writing file\"); e.printStackTrace(); System.exit(1); } finally { if(f != null) { f.close(); } } //reading from a file RandomAccessFile fin = null; try { fin = new RandomAccessFile(\"emp.dat\", \"r\"); Employee em = new Employee(); System.out.println(\"Number of records = \" + em.size(fin) + \"\n\"); for(int i = 0; i < 4; i++) { em.read(fin, random[i]); System.out.print(\"Record #\" + (i+1) + \": \"); em.show(); } } catch(IOException e) { System.err.println(\"Error reading file\"); e.printStackTrace(); System.exit(1); } finally { if(fin != null) fin.close(); } }}โปรแกรมตวั อยา งของเราใช array 4 ตัวเปน ตัวเก็บ record ทีต่ อ งการเขยี นไปยงั ไฟล และเพอื่ เปนการแสดงใหเหน็ ถงึ การเขาหาไฟลใ นรูปแบบของความเปน random เราจึงใช array random เปนตวั กาํ หนดถงึ ตาํ แหนง ของ record ที่เราตองการจะเขยี น ซึ่งเราไดกําหนดให ภาควิชาคอมพิวเตอรธุรกจิ วิทยาลยั ฟารอีสเทอรน

บทท่ี 8 Streams I/O 231เร่มิ ตนกบั JavaRecord ตวั แรกเขียนในตําแหนงที่ 2 (random[0])Record ตวั ทีส่ องเขียนในตาํ แหนงที่ 3 (random[1])Record ตัวท่ีสามเขยี นในตาํ แหนง ท่ี 0 (random[2])Record ตวั ทสี่ ดุ ทา ยเขียนในตําแหนงที่ 1 (random[3])เราเก็บขอมูลเหลาน้ีดว ยการสรา ง object จาก class Employee ซ่ึงเปน class ที่ทําหนาทหี่ ลกั ในการเขยี น และอา น record ไปยัง และออกจากไฟล ตามลําดบั ซ่งึ มี code ดังน้ี//Employee.java - Simple record for random-access fileimport java.io.*;import java.io.RandomAccessFile;import java.lang.String;class Employee {private String firstName; //15 characters (30 bytes)private String lastName; //15 characters (30 bytes)private int year; //4 bytesprivate double salary; //8 bytesprivate static final int RECORD_SIZE = 72;//default constructorEmployee() { firstName = \"\"; lastName = \"\"; year = 0; salary = 0.0D;}//setting up fieldsEmployee(String firstName, String lastName, int year, double salary) { this.firstName = firstName; this.lastName = lastName; this.year = year; this.salary = salary;}//write a record to a file with a given positionpublic void write(RandomAccessFile file, int position) throws IOException { try { //locate a position file.seek((long)(position * RECORD_SIZE)); //write equal-length strings writeString(file, firstName, 15); writeString(file, lastName, 15); //write int and double file.writeInt(year); file.writeDouble(salary); } catch(IOException e) { System.err.println(\"Error writing file\"); e.printStackTrace(); System.exit(1); }} ภาควิชาคอมพิวเตอรธรุ กิจ วิทยาลยั ฟารอีสเทอรน

บทท่ี 8 Streams I/O 232เรม่ิ ตนกับ Java//reading a record from a file with a given positionpublic void read(RandomAccessFile file, int position) throws IOException { try { //locate position to read file.seek((long)(position * RECORD_SIZE)); //reading strings firstName = readString(file, 15); lastName = readString(file, 15); //reading int and double year = file.readInt(); salary = file.readDouble(); } catch(IOException e) { System.err.println(\"Error reading file\"); e.printStackTrace(); System.exit(1); }}//helper method to write a string with specified lengthpublic void writeString(DataOutput out, String s, int len) throws IOException { for(int i = 0; i < len; i++) { if(i < s.length()) out.writeChar(s.charAt(i)); else out.writeChar(0); }}//helper method to read a stringpublic String readString(DataInput in, int len) throws IOException { String s = \"\"; int i = 0; while(i < len) { char c = in.readChar(); if(c != 0) s += c; i++; } return s;}//number of records in filepublic int size(RandomAccessFile file) throws IOException{ int size = 0; try { size = (int)file.length() / RECORD_SIZE; } catch(IOException e) { System.err.println(\"Error reading file.\"); System.exit(1); } return size;} ภาควิชาคอมพิวเตอรธรุ กจิ วิทยาลยั ฟารอีสเทอรน

บทที่ 8 Streams I/O 233เร่มิ ตนกับ Java //display a record to screen public void show() { System.out.print(firstName + \" \"); System.out.print(lastName + \" \"); System.out.print(year + \" \"); System.out.println(salary); }}method หลกั ๆ ท่ีอยูใน class Employee คอืwrite(RandomAccessFile, position)read(RandomAccessFile, position)writeString(DataOutptu, String, length)readString(DataInput, length)size(RandomAccessFile)เน่ืองจากวาเราตอ งรขู นาดของ record ของเราวา มคี วามยาวเทา ไร เราจงึ จะสามารถทจ่ี ะเล่อื น logicalpointer ของเราไปยงั ตาํ แหนง ตาง ๆ ที่เราตอ งการได ดงั นน้ั เราจึงตอ งกําหนดขนาดของ record ภายในโปรแกรมของเราเพอื่ ใหก ารทาํ งานสะดวกขน้ึ ทงั้ นก้ี ารกาํ หนดขนาดกต็ องขนึ้ อยกู ับการเลือกใชว ธิ กี ารเขียนของเราวาใช method ตัวไหนเปน ตัวเขียน ถา เราใช writeUTF() เราก็ตองกาํ หนดขนาดแบบหนึง่แตถ า เราใช writeChars() เรากต็ องกําหนดขนาดอกี แบบหนง่ึ (ดูความแตกตางของการใชจ ากตาราง)สําหรบั โปรแกรมท่เี ราเขยี นขึน้ เรากําหนดใหข นาดของ record เปน 72 byte กเ็ พราะวาเราใชwriteChar() เปนตวั เขยี น ดังน้ัน ทั้งช่ือและนามสกุลใช 30 byte สว น year และ salary ใช 4 และ 8byte ตามลาํ ดบัหนาท่ขี อง write() คือ การนาํ ขอ มลู จาก field ตา ง ๆ ของ Employee object เขา สูไฟลในตําแหนงทไี่ ดกําหนดไว ดว ยการใช seek() เปน ตวั กําหนดตําแหนงfile.seek((long)(position * RECORD_SIZE));เราคูณ position ดว ย RECORD_SIZE ก็เพ่ือท่จี ะหาตาํ แหนง ไดถ ตู อ ง เน่อื งจากวา เรากําหนดให field 2ตวั แรกมคี วามยาวเทา กับ 15 ตวั อักษร (30 byte) หลังจากนนั้ เราก็เขียน field ทัง้ สองไปยงั ไฟลด ว ยการเรยี กใช writeString() ซ่งึ ทาํ หนาทใ่ี นการเขยี นจํานวน byte ที่ไดกาํ หนดไว และจะเขยี นคา 0 ในตําแหนงที่วา งอยู ถา ความยาวของ field ที่เขียนมนี อ ยกวา 15 ตัวอักษร//write equal-length stringswriteString(file, firstName, 15);writeString(file, lastName, 15);เมือ่ เราเขยี น field ทัง้ สองเสรจ็ เรากเ็ ขียน อีกสอง filed ท่เี หลอื ดว ย writeInt() และ writeDouble() โดยไมตอ งทําอะไรพิเศษ//write int and doublefile.writeInt(year);file.writeDouble(salary);code ของ writeString() กไ็ มยากอะไร เราเขยี นขอมูลทลี ะตวั ไปยงั ไฟลจ นกวา จะหมดขอ มลู ท่อี ยใู นstring ถาความยาวของ string ทเ่ี ราเขยี นมนี อ ยกวาความยาวทีก่ าํ หนดไว เรากเ็ ขียนคา 0 ลง ณ ตาํ แหนงน้ันpublic void writeString(DataOutput out, String s, int len) throws IOException { for(int i = 0; i < len; i++) { if(i < s.length()) out.writeChar(s.charAt(i)); else ภาควิชาคอมพิวเตอรธรุ กจิ วทิ ยาลยั ฟารอสี เทอรน

บทที่ 8 Streams I/O 234เร่ิมตน กับ Java } out.writeChar(0);}ในการอาน filed กลบั ออกมาก็เหมอื นกนั หลงั จากทใี่ ช seek() หาตาํ แหนง ไดแ ลว เรากเ็ รียกใชreadString() ในการอานสอง field แรก และใช readInt() กับ readDouble() ในการอา นอกี สอง field ที่เหลือCode ของ readString() กง็ า ย ๆ เราทําการอานทุกตวั แตจ ะเก็บไวเ ฉพาะตวั ทไ่ี มใ ช 0 เพราะ 0 เปน คา ที่เราใชแ ทนตาํ แหนงที่วางในการเขียน string เขา สูไ ฟลpublic String readString(DataInput in, int len) throws IOException { String s = \"\"; int i = 0; while(i < len) { char c = in.readChar(); if(c != 0) s += c; i++; } return s;}เราใช readChar() ในการอานขอ มลู แตล ะตวั และเราจะตรวจสอบวา คาทอี่ า นไดเ ปน 0 หรอื ไม ถา ไมเ ราก็เชอ่ื มคานเี้ ขาสู string s พรอ มกับเลื่อนไปอานขอมูลตัวตอไป ทาํ การอานและเชอ่ื มจนกวา จะหมดขอมลูสาํ หรับการหาจาํ นวนของ record ที่มอี ยใู นไฟลน้ันเราหาไดดว ยการใช ขนาดของไฟลห ารดว ยขนาดของrecord ทเ่ี ราไดก าํ หนดไวpublic int size(RandomAccessFile file) throws IOException{ int size = 0; try { size = (int)file.length() / RECORD_SIZE; } catch(IOException e) { System.err.println(\"Error reading file.\"); System.exit(1); } return size;}เราใช readChar() และ writeChar() ในการเขียนและอา นขอ มลู ดงั นัน้ เราตอ งคาํ นึงถึงจํานวนของ byteท่ีเราตอ งใชส ําหรับ record แตละตวั วาถกู ตอ งตามที่ไดก าํ หนดหรอื ไม สิง่ ที่ตอ งคาํ นึงถงึ ในเรื่องของการใช random access file ก็คอื field แตละ field ควรเปน field ทีม่ ขี นาดตายตัว เพราะจะทําใหการคน หาตาํ แหนงทาํ ไดอ ยา งถกู ตอ งผลลพั ธท เ่ี ราไดจ ากการ run คอืNumber of records = 4Record #1: John Kawakami 1965 2400.0Record #2: Paul Collins 1978 500.0Record #3: Stephen Anderson 1985 5000.0Record #4: Hendrix McCoy 1972 9500.0เรามาลองดตู ัวอยา งการปรบั ปรงุ ขอ มลู (update) ทีอ่ ยใู นไฟลก นั ภาควิชาคอมพิวเตอรธรุ กิจ วทิ ยาลยั ฟารอีสเทอรน

บทที่ 8 Streams I/O 235เริ่มตน กบั Javaการ update ขอมูลกค็ ลาย ๆ กับการเขยี นขอ มลู เขาสูไฟล เราตองหาตาํ แหนงของ record ทตี่ องการupdate ใหเ จอ ซ่ึงเม่อื เจอแลว การเปล่ียนแปลงขอ มลู กส็ ามารถทาํ ได เราเลอื กทจี่ ะเปลย่ี นแปลง recordของเราทกุ field เพ่ือเปน การแสดงถึงวธิ ีการในการ update แตในทางปฏบิ ตั จิ ริง คงไมมใี ครทาํ แบบน้ีคําสงั่ หลัก ๆ ในการ update คือf.seek((long)(recNum – 1) * em.recSize());em.write(f, recNum – 1);record ของเราถกู เก็บในตําแหนงทน่ี อยกวา ทีเ่ ปนจริงอยหู นึง่ คา ดงั น้นั การใช seek() เราจึงตอ งหักออกหนึง่ คา เราไดเขยี น method ขึน้ ใหมอกี หลายตวั เพอ่ื ชวยใหก ารกาํ หนด และ การดึงขอ มลู ออกจากrecord ทําไดโดยไมม ปี ญ หา method ทเี่ พม่ิ ข้ึนใน class Employee คอืpublic void setFirstName(String name) { firstName = name;}public void setLastName(String name) { lastName = name;}public void setSalary(double pay) { salary = pay;}public int recSize() { return RECORD_SIZE;}public void setYear(int y) { year = y;}สาํ หรบั กระบวนการหลัก ๆ ท่เี กี่ยวขอ งกบั การ update ขอมลู ก็ไมมีอะไรมาก หลังจากทรี่ บั ขอ มูลใหมมาจาก keyboard แลว พรอ มกับหาตําแหนงทต่ี อ งการ update เจอเราก็ทําการเขียนขอ มูลใหมท บั ลงทเี่ ดมิ …System.out.print(\"Enter record number: \");buffer = new BufferedReader(new InputStreamReader(System.in));str = buffer.readLine();recNum = Integer.parseInt(str);System.out.print(\"Enter first name: \");emp.setFirstName(buffer.readLine());System.out.print(\"Enter last name: \");emp.setLastName(buffer.readLine());System.out.print(\"Enter year of birth: \");emp.setYear(Integer.parseInt(buffer.readLine()));System.out.print(\"Enter salary: \");emp.setSalary(Double.parseDouble(buffer.readLine()));และ code สําหรบั การเขยี นทบั ท่ีเราไดพ ดู กอ นหนา นี้ …f.seek((long)(recNum – 1) * em.recSize());em.write(f, recNum – 1);ผลลพั ธข องการ run>java Update temp.dat ภาควิชาคอมพิวเตอรธุรกจิ วทิ ยาลยั ฟารอ ีสเทอรน

บทท่ี 8 Streams I/O 236เริ่มตนกบั JavaEnter record number: 1Enter first name: My nameEnter last name: Is changingEnter year of birth: 1965Enter salary: 2500Record #1: My name Is changing 1965 2500.0Record #2: Hendrix McCoy 1972 9500.0Record #3: John Kawakami 1965 2400.0Record #4: John Kowalski 1990 5400.0>java Update temp.datEnter record number: 3Enter first name: JennieEnter last name: SaiudomEnter year of birth: 1995Enter salary: 500Record #1: My name Is changing 1965 2500.0Record #2: Hendrix McCoy 1972 9500.0Record #3: Jennie Saiudom 1995 500.0Record #4: John Kowalski 1990 5400.0โปรแกรมตวั อยา งน้ี update ทกุ field ทีม่ ีอยูใน record ดวยการกาํ หนดขอมลู ทเี่ ขา มาใหมใ หกบั objectจาก class Employee เสร็จแลวกเ็ ขียน object ใหมนี้ลงในไฟล ซง่ึ การกระทําแบบนเ้ี ราไมส ามารถทีจ่ ะupdate บาง field ที่มีอยไู ด เราตอ ง update ทั้งหมด สาํ หรบั การ update เฉพาะ field ท่ตี อ งการนนั้ จะทงิ้ ไวใหเปนแบบฝก หัดทา ยบทตอไปตวั โปรแกรมทง้ั หมด มดี ังนคี้ ือ//Update.java - Updating Random-access fileimport java.io.RandomAccessFile;import java.io.*;import java.lang.Integer;class Update { public static void main(String[] args) throws IOException { RandomAccessFile f = null; Employee em = new Employee(); if(args.length < 1) { System.err.println(\"Usage: Update file-name\"); System.exit(1); } try { f = new RandomAccessFile(args[0], \"rw\"); int recNum = getNewData(f, em); //get new data updateData(f, recNum, em); //update record showData(f, args[0]); //display records } catch(IOException e) { System.err.println(\"Error processing file\"); e.printStackTrace(); System.exit(1); }} ภาควิชาคอมพิวเตอรธ ุรกจิ วิทยาลัยฟารอสี เทอรน

บทท่ี 8 Streams I/O 237เริม่ ตน กับ Java//get new data from keyboardprivate static int getNewData(RandomAccessFile f, Employee emp) throws IOException { BufferedReader buffer = null; InputStreamReader iStream = null; String str = \"\"; int recNum = 0; try { System.out.print(\"Enter record number: \"); buffer = new BufferedReader( new InputStreamReader(System.in)); str = buffer.readLine(); recNum = Integer.parseInt(str); System.out.print(\"Enter first name: \"); emp.setFirstName(buffer.readLine()); System.out.print(\"Enter last name: \"); emp.setLastName(buffer.readLine()); System.out.print(\"Enter year of birth: \"); emp.setYear(Integer.parseInt(buffer.readLine())); System.out.print(\"Enter salary: \"); emp.setSalary(Double.parseDouble(buffer.readLine())); } catch(IOException e) { System.err.println(\"Error readin file\"); e.printStackTrace(); System.exit(1); } return recNum; //record number}//update recordprivate static void updateData(RandomAccessFile f, int recNum, Employee em) throws IOException { try { //locate record f.seek((long)(recNum – 1) * em.recSize()); //write the whole record em.write(f, recNum – 1); } catch(IOException e) { System.err.println(\"Error writing file\"); e.printStackTrace(); System.exit(1); } finally { if(f != null) f.close(); }}//display all records in this fileprivate static void showData(RandomAccessFile f, String fName) throws IOException { try { f = new RandomAccessFile(fName, \"r\"); Employee em = new Employee(); ภาควิชาคอมพิวเตอรธ รุ กิจ วิทยาลัยฟารอสี เทอรน

บทที่ 8 Streams I/O 238เร่ิมตน กบั Java int num = em.size(f); for(int i = 0; i < 4; i++) { em.read(f, i); System.out.print(\"Record #\" + (i+1) + \":\"); em.show(); } } catch(IOException e) { System.err.println(\"Error reading file\"); e.printStackTrace(); System.exit(1); } finally { if(f != null) f.close(); } }}สรุปเราไดแ สดงตวั อยา งของการทาํ งานกับ text file และ binary file การอาน การเขยี น รวมไปถึงกระบวนการตา ง ๆ ทีเ่ กยี่ วของกับไฟล โดยสรปุ แลวเราไดพ ดู ถึง9 การตรวจสอบขอ มูลทเ่ี ก่ยี วของกบั ไฟลดวย File และ method ตาง ๆ เชน ifFile() canRead() เปน ตน9 การใช FileReader FileWriter FileInputStream FileOutputStream9 การใช DataOutputStream BufferedOutputStream9 การใช StreamTokenizer และ StringTokenizer9 การสรางและใชงาน text file9 การใช delimiter ในการอา นขอ มลู จาก text file9 การสรางและใชงาน binary file9 การสรา งและใชงาน Random-access file9 การ update ขอมูลใน random-access fileแบบฝก หดั1. จงเขียนโปรแกรมทท่ี าํ หนาทแ่ี สดงขอ มลู เก่ียวกบั ไฟลท ุกตัวทม่ี ีอยใู น directory นั้น ๆ เชน ถา เจอ ไฟลใหแ สดงถงึ ขนาด วันทส่ี ราง ถาเจอ directory ใหแ สดงถึงจาํ นวนไฟลท ี่มีอยใู น directory น้นั พรอ มกบั วนั ท่ี directory นี้ถูกสรางขึน้2. จงเขยี นโปรแกรมท่ี copy ขอ มูลจากไฟลห นง่ึ ไปยงั อีกไฟลห น่ึงผานทาง command-line3. จงเขียนโปรแกรมทสี่ รา งขอ มลู ชนดิ int ดวยการสมุ จาํ นวนเทากับ 100 ตัว หลังจากนั้นใหน ําขอ มลู ท้ังหมดไปเก็บไวใน text file โดยกาํ หนดใหจ าํ นวนของขอ มลู ตอแถวเทากับ 10 ตัว4. จงเขยี นโปรแกรมทีอ่ านขอมูลจากไฟลท ่ีเขยี นขนึ้ ในขอ 3 เสร็จแลวใหค าํ นวณหาผลรวมของขอ มลู ใน แตล ะแถว หลงั จากน้นั ใหเขียนขอมูลในแตล ะแถวรวมทั้งผลรวมท่ีหาไดล งในไฟลตัวเดิม (ขอมลู ใน แตละแถวจะมจี าํ นวนเทากบั 11 ตวั โดยทต่ี วั สดุ ทายในแถวเปน ผลรวมของขอมลู ในแถวนั้น)5. จงปรบั ปรงุ โปรแกรมที่เขยี นขน้ึ ในขอ 4 โดยใหมีการคํานวณหาคา เฉลี่ยของขอมลู ทุกตวั ในแนวตงั้ (column) นาํ ผลลพั ธทไี่ ดพรอ มทั้งขอมูลในแตล ะแถวไปเก็บไวในไฟลต ัวใหม6. จงเขยี นโปรแกรมทอี่ า นขอ มูลในรูปแบบที่กาํ หนดใหดานลางนี้ หลงั จากนั้นใหแ สดงขอ มูลท่ีอา นได ไปยังหนาจอ โดยไมตองแสดง delimiter ทีใ่ ช ใหก ําหนดจํานวนของขอมูลท่มี อี ยใู นไฟลจ าํ นวน เทา กับ 10 แถว ภาควิชาคอมพิวเตอรธ รุ กิจ วิทยาลัยฟารอีสเทอรน

บทท่ี 8 Streams I/O 239เรมิ่ ตน กบั Java John Longman+25.0+30.50+48.00 Peter Wang+35.00+50.00+98.00 … … Mike Kawakami+90.00+80.00+85.007. จงเขยี นโปรแกรมทส่ี รา ง binary file จาก class Student ทก่ี ําหนดใหน ี้ โดยทําการอา นขอ มลู เบ้อื งตน มาจาก keyboard ซ่งึ มีขอมลู ดงั นี้ ช่อื ตน เปน String จาํ นวน 15 ตัวอักษร นามสกุล เปน String จํานวน 15 ตัวอักษร เกรด เปน array ท่ีเกบ็ double เชน 85.0 90.5 ทง้ั นจี้ ํานวนของเกรดทีม่ ีอยจู ะมกี ต่ี วั ก็ได เสร็จแลว ใหท าํ การอา นขอ มูลกลับออกมาจากไฟล พรอมทงั้ คาํ นวณหาเกรดเฉลย่ี ของขอมูล (นักศึกษา) ทุกตัว เมือ่ ไดเ กรดเฉล่ียแลว ใหแสดงผลออกทางหนา จอ class Student { String firstName; String lastName; double[] grades; }8. จงเขียนโปรแกรมทสี่ รา ง random-access file จากโครงสรางของ Student ทีม่ ีอยใู นขอ 7 โดยให user เปนผกู ําหนดตาํ แหนงของ record ทต่ี อ งการเขียนเอง ใหเขยี น method ที่แสดงขอ มูลของ record (ทกี่ ําหนดมาจาก keyboard) ไปยงั หนา จอ9. จงปรบั ปรงุ โปรแกรม Update ในบทนใ้ี หมีการ update ไดเ ฉพาะ field ที่เปน salary เทานนั้10. จงปรบั ปรงุ โปรแกรมในขอ 6 ดว ยการเพ่มิ method ในการคาํ นวณหาผลรวมของขอ มลู ในแตละแถว หลงั จากน้ันใหน าํ ขอมลู ทงั้ หมดไปเก็บไวใ นไฟลตวั ใหม โดยใหผ ลรวมทหี่ าไดเ ปน ขอมูลตวั สดุ ทาย ในแถวนนั้ ภาควิชาคอมพิวเตอรธ ุรกิจ วิทยาลยั ฟารอีสเทอรน

ตารางตาง ๆ 240เรม่ิ ตนกบั Javaตารางตาง ๆตารางที่ 1 Unicode characters – 128 ตัวแรกdec hex char Dec hex char dec hex char dec hex char 66 0042 B 99 0063 c0 0000 <NUL> 33 0021 ! 67 0043 C 100 0064 d 68 0044 D 101 0065 e1 0001 <SOH> 34 0022 \" 69 0045 E 102 0066 f 70 0046 F 103 0067 g2 0002 <STX> 35 0023 # 71 0047 G 104 0068 h 72 0048 H 105 0069 i3 0003 <ETX> 36 0024 $ 73 0049 I 106 006A j 74 004A J 107 006B k4 0004 <EOT> 37 0025 % 75 004B K 108 006C l 76 004C L 109 006D m5 0005 <ENQ> 38 0026 & 77 004D M 110 006E n 78 004E N 111 006F o6 0006 <ACK> 39 0027 ' 79 004F O 112 0070 p 80 0050 P 113 0071 q7 0007 <BEL> 40 0028 ( 81 0051 Q 114 0072 r 82 0052 R 115 0073 s8 0008 <BS> 41 0029 ) 83 0053 S 116 0074 t 84 0054 T 117 0075 u9 0009 <HT> 42 002A * 85 0055 U 118 0076 v 86 0056 V 119 0077 w10 000A <LF> 43 002B + 87 0057 W 120 0078 x 88 0058 X 121 0079 y11 000B <VT> 44 002C ' 89 0059 Y 122 007A z 90 005A Z 123 007B {12 000C <FF> 45 002D - 91 005B [ 124 007C | 92 005C \ 125 007D }13 000D <CR> 46 002E . 93 005D ] 126 007E ~ 94 005E ^ 127 007F <DEL>14 000E <SO> 47 002F / 95 005F _ 128 0080 96 006015 000F <SI> 48 0030 0 97 0061 a 98 0062 b16 0010 <DLE> 49 0031 117 0011 <DC1> 50 0032 218 0012 <DC2> 51 0033 319 0013 <DC3> 52 0034 420 0014 <DC4> 53 0035 521 0015 <NAK> 54 0036 622 0016 <SYN> 55 0037 723 0017 <ETB> 56 0038 824 0018 <CAN> 57 0039 925 0019 <EM> 58 003A :26 001A <SUB> 59 003B ;27 001B <ESC> 60 003C <28 001C <FS> 61 003D =29 001D <GS> 62 003E >30 001E <RS> 63 003F ?31 001F <US> 64 0040 @32 0020 blank 65 0041 Aตารางท่ี 2 Constants ท่ใี ชบ อย ๆ ในโปรแกรม ความหมายชือ่ คา ของ e (natural logarithm)Math.E คา ของ PI (3.145)Math.PI infinity ที่เปนลบFloat/Double.NEGATIVE_INFINITY infinity ทีเ่ ปนบวกFloat/Double.POSITIVE_INFINITY ไมใชตวั เลขFloat/Double.NaN คาสูงสุดByte/Short/Integer/Long/Float/Double.MAXIMUM_VALUE คา ตํ่าสดุByte/Short/Integer/Long/Float/Double.MINIMUM_VALUE ทางเขาขอ มลู (keyboard)System.in ทางออกขอมูล (จอ)System.out ทางออกของ error (จอ)System.err ภาควิชาคอมพิวเตอรธ รุ กจิ วทิ ยาลัย ฟารอสี เทอรน

ตารางตาง ๆ 241เริม่ ตน กบั Javaตารางที่ 3 Numeric Types คาตาํ่ สดุ คาสูงสุดชนิด bit คาเบอ้ื งตน -128 127byte 8 0 -32768 32767short 16 0 -2147483648 2147483647int 32 0 -9223372036854775808 9223372036854775807long 64 0 1.40129846432481707e-45f 3.40282346638528860e+38ffloat 32 0.0f 4.94065645841246544e-324 1.79769313486231570e+308double 64 0.0dตารางที่ 4 Escape Sequences ความหมายEscape Sequence back space\b tab\t LF (ข้ึนบรรทัดใหม)\n FF (ขึน้ หนาใหม)\f CR (กลบั ไปยงั จดุ เริ่มตน)\r double quote\\" single quote\' back slash\\ Unicode จาก \u ตามดว ยเลขฐาน 16 ส่ีตวั\uxxxx เลขฐานแปด เชน \101\xxxตารางที่ 5 Format Syntax สาํ หรบั ตวั เลขform คา ผลลัพธ ความหมาย 0 –ใชแ ทน digit0000 314 0314 # - ใชแทน digit . - จุดทศนยิ ม###0 314 314 , - ใชแ บงกลุมตัวเลข % - คูณตวั เลขดว ย 100 เพ่อื แสดง %##0.0# 3.10 3.1 \u00A4 – แสดงสกลุ เงินตาม locale ของประเทศ#,##0 3000 3,000##0.00% 3.1415 314.15%\u00A4##0 314 $314 ภาควิชาคอมพิวเตอรธรุ กิจ วิทยาลัย ฟารอสี เทอรน


Like this book? You can publish your book online for free in a few minutes!
Create your own flipbook