Upload
others
View
7
Download
0
Embed Size (px)
Citation preview
บทท 10
การอาน และเขยนแฟมขอมล Read and Write Files คลาส FileInputStream และ FileOutputStream ใชในการอานและเขยนขอมลแบบ Binary สวนคลาส FileReader และ FileWriter ใชในการอานและเขยนขอมลแบบ Character โปรแกรม ReadFile.java แสดงการอานขอมลจากแฟมขอมลทชอ Hello.txt ซงเปนแฟมขอมลชนดตวอกษร โดยใชคลาส FileReader ในการอานขอมล
import java.io.*;
public class ReadFile {
public static void main(String[] args) {
String filename = "hello.txt";
File myFile = new File(filename);
if ( !myFile.canRead() ) {
System.out.println(filename+ " is not readable");
System.exit(1);
}
try {
FileReader input_file = new FileReader(myFile);
int c;
while ( ( c = input_file.read()) != -1 ) { // ตรวจสอบสถานะ End of Line
System.out.print( (char) c ); // Casting จาก int ไปเปน char }
}
catch (FileNotFoundException e) {
System.out.println("Error file is not found");
System.exit(1);
}
catch (IOException e) {
System.out.println("Error while reading the file");
System.exit(1);
}
} // จบ main
}
---------- Java Output----------
Hello, how are you?
This text file is used for test FileReader.
Thank you.
Binary
Character
FileInputStream FileOutputStream
FileReader FileWriter
การเขยนโปรแกรมภาษา Java 165
คลาส FileInputStream คลาส FileReader คลาส FileOutputStream และคลาส FileWriter สามารถน ามาใชในการอานหรอเขยนขอมลได แตไมเหมาะส าหรบการอานหรอเขยนขอมลชนด Primitive (เชน Integer หรอ Double ยกเวน Byte) เพราะคลาสทง 4 ถกออกแบบมาใหอานเขยนขอมลครงละ 8 บต หรอ 1 ไบตเทานน ในการใชงานจรงจ าเปนตองใชคลาสอนๆ ใน Package java.io ควบคไปดวย ตามทแสดงไวในตารางท 10.1
ตารางท 10.1 แสดงคลาสทใชในการอานและเขยนแฟมขอมล รปแบบการอานเขยน รปแบบคลาสทใช
อานขอมลตวอกษรจาก Text File ครงละ 1 ค า StreamTokenizer (new BufferedReader (new InputStreamReader(new FileInputStream)))
อานขอมลตวอกษรจาก Text File ครงละบรรทด BufferedReader (new InputStreamReader (new FileInputStream))
เขยนขอมลชนด Primitive ไปเปน Text File PrintWriter (new FileOutputStream) เขยนขอมลชนด Primitive ไปเปน Binary File DataOutputStream (new FileOutputStream) อานขอมลชนด Primitive จาก Binary File DataInputStream (new FileInputStream)
การอานขอมลตวอกษรจาก Text File ครงละ 1 ค า การอานขอมลครงละ 1 ค าจากตวอกษรสามารถใชรปแบบคลาสดงตวอยาง
StreamTokenizer (new BufferedReader (new
InputStreamReader(new
FileInputStream)));
คลาส BufferedReader ใชส าหรบจองหนวยความจ า (Buffer) ส าหรบการอานขอมลจ านวนมาก ซงตองใชคกบคลาส InputStreamReader เสมอ เนองจากคลาส FileInputStream ไมสามารถเปน Parameter ใน Constructor ของ BufferedReader ไดโดยตรง
การอ านข อม ล โดยใชคลาส StreamTokenizer ไดกล าว ไปแล ว ในบทท 8 โปรแกรม Read1WordFromTextFile.java แสดงการอานขอมลจาก Hello.txt ครงละ 1 ค า โดยขอมลใน Hello.txt คอ
Hello, how are you? This text file is used for test FileReader. Thank you.
166 การเขยนโปรแกรมภาษา Java
import java.io.*;
public class Read1WordFromTextFile {
public static void main(String[] args) {
// แฟมขอมลชอ Hello.txt String filename = "Hello.txt";
File myFile = new File(filename);
// ตรวจสอบกอนวา Hello.txt มอยจรงโดยใช Method canRead() if ( !myFile.canRead() ) {
System.out.println(filename+ " is not readable");
System.exit(1);
}
// สรางวตถ StreamTokenizer จาก BufferedReader try {
StreamTokenizer token = new StreamTokenizer (
new BufferedReader (
new InputStreamReader (
new FileInputStream (myFile))));
/* ถาไมมการใช Method whitespaceChars() โปรแกรมจะใช ชองวางในการตดค า การใชค าสง whitespaceChars() เพอเพมตวอกษรทเปน White space เชน ; หรอ ? ดวย ท าใหโปแกรมจะตดค าโดยไมสนใจเครองหมาย ดงตอไปน */ token.whitespaceChars('.','.');
token.whitespaceChars(',',',');
token.whitespaceChars('!','!');
token.whitespaceChars('?','?');
int ttype=0;
// ค าสง nextToken() เพออานค า ttype = token.nextToken();
while ( ttype != StreamTokenizer.TT_EOF) { // ทดสอบวาไมใช End of file
if(ttype == StreamTokenizer.TT_NUMBER) {
System.out.println(token.nval);
}
else {
System.out.println(token.sval);
}
ttype = token.nextToken(); // Read word
} // จบ while
} // จบ try catch (FileNotFoundException e) {
System.out.println("Error file is not found");
System.exit(1);
การเขยนโปรแกรมภาษา Java 167
}
catch (IOException e) {
System.out.println("Error while reading the file");
System.exit(1);
}
} // จบ main
}
---------- Java Output----------
Hello
how
are
you
This
text
file
is
used
for
test
FileReader
Thank
you
การอานขอมลตวอกษรจาก Text File ครงละบรรทด คลาสทใชในการอานขอมลทละบรรทดจากแฟมขอมลคอคลาส BufferedReader เหตผลทใชคลาสนเนองจากคลาสนม Method readLine() ซงเหมาะสมในการใชในการอานขอมลชนดตวอกษรเปนบรรทดซงมรปแบบการสรางคลาสดงตอไปน BufferedReader(new InputStreamReader(new FileInputStream));
โปรแกรม ReadLineFromTextFile.java แสดงการอานขอมลจาก Hello.txt ครงละ 1 บรรทดโดยใช
Method readLine() ของคลาส BufferedReader ในกรณทอานจนกระทงไปถงทายแฟมขอมล Method readLine() จะสงคากลบเปน Null ซงสามารถใชในการตรวจสอบจดสนสดของแฟมขอมลนนเอง import java.io.*;
public class ReadLineFromTextFile {
public static void main(String[] args) {
String filename = "Hello.txt";
File myFile = new File(filename);
if ( !myFile.canRead() ) {
System.out.println(filename+ " is not readable");
System.exit(1);
}
try {
BufferedReader reader = new BufferedReader (
new InputStreamReader (
new FileInputStream (myFile)));
String st = reader.readLine();
while( st != null ){
168 การเขยนโปรแกรมภาษา Java
System.out.println( st );
st = reader.readLine();
}
} // จบ try catch (FileNotFoundException e) {
System.out.println("Error file is not found");
System.exit(1);
}
catch (IOException e) {
System.out.println("Error while reading the file");
System.exit(1);
}
} // จบ main
}
---------- Java Output----------
Hello, how are you?
This text file is used for test FileReader.
Thank you.
การเขยนขอมลชนด Primitive ไปเปน Text File คลาส PrintWriter สามารถใชเขยนขอมล Primitive ไปยง Text File ดงโปรแกรม WriteTextFile.java ในคลาส PrintWriter ม Method print() และ printlin() ทใชในการเขยนขอมลไปท Text File เมอมการเขยนขอมลแลวตองเรยกใช Method flush() ดวยเพราะการเขยนขอมลโดยใชค าสง print() หรอ println() เปนการเขยนขอมลไปท Buffer เทานน การเรยกใช Method flush() เพอใหเขยนขอมลลงดสกทนท สวน Method close() เปนการจบการเขยนขอมลไปทแฟมขอมล โปรแกรม WriteTextFile.java แสดงการเขยนขอมลตวอกษร ตวเลขจ านวนเตมและทศนยม ไปทแฟมขอมลเดยวกน import java.io.*;
public class WriteTextFile {
public static void main(String[] args) {
PrintWriter writer=null;
try {
writer = new PrintWriter (
new FileOutputStream (
new File("output.txt")));
}
// ตรวจสอบในกรณทไมสามารถเปดแฟมขอมลได catch (FileNotFoundException e) { System.out.println("Error file is not found");
System.exit(1);
}
writer.println("Hello how are you CS316”);
writer.println("This line will print String");
writer.println("Line below will write integer");
int i = 100;
writer.println(i);
double d = 123456.123456;
writer.println("Line below will write double");
writer.print(d);
การเขยนโปรแกรมภาษา Java 169
writer.flush(); writer.close();
} // จบ main
}
จากตารางท 10.1 สงเกตไดวา ไมมการอานขอมลทเปน Primitive จาก Text File เพราะเมอมการเขยน
ขอมลชนด Primitive ไปท Text File แลว ขอมลทถกเขยนจะเปลยนเปน Character เชนคา Integer 123 เมอเขยนจะมคาเปนตวอกษร ‘1’ ‘2’ และ ‘3’ ดงนนการอานขอมลกลบมาเปน Integer ผเขยนโปรแกรมจ าเปนตองทราบจ านวนหลกทแนนอนของขอมลทตองการอาน อยางไรกตาม ผเขยนโปรแกรมสามารถใชชองวางเปนตวแบงในการเกบคาได และสามารถใชคลาส StreamTokenizer อานคา กลบเปน Integer ดงโปรแกรม Read1WordFromTextFile.java ทแสดงไวแลวในชวงตน
เขยนขอมลชนด Primitive ไปท Binary File การเขยนขอมลชนด Primitive ไปท Binary File ท าไดโดยใชคลาส DataOutputStream และตองเรยก Method flush() ทกครงเพอใหขอมลทอยใน Buffer เขยนลงไปทดสกเหมอนค าสง flush() ในคลาส PrintWriter กอนการเขยนขอมลไปทแฟมขอมลควรมการตรวจสอบวาแฟมขอมลนนไมไดมอยกอนเพอปองกนไมใหเขยนขอมลทบแฟมขอมลเดมทมอย โปรแกรม WriteToBinary.java แสดงการเขยนขอมลชนด Integer คา 0 ถง 9 ไปทแฟมขอมลชอ ‚output.dat‛ และไมสามารถเปดอานไดโดย Text Editor ทวไป เนองจากเปนขอมลชนด Binary import java.io.*;
public class WriteToBinary {
public static void main(String[] args) {
File myFile = new File("output.dat");
if( myFile.isFile() ) {
System.out.println("Error, file exists");
System.exit(1);
}
try {
// สรางวตถ DataOutputStream ขน DataOutputStream output = new DataOutputStream (new
FileOutputStream (myFile));
// เขยนตวเลข 0 ถง 9 ไปทแฟมขอมล for(int i=0; i<10; i++) {
output.writeInt(i);
}
output.flush();
output.close();
}
catch (FileNotFoundException e) {
System.out.println("Error, cannot create the file");
System.exit(1);
}
catch (IOException e) {
System.out.println("Error while reading the file");
System.exit(1);
170 การเขยนโปรแกรมภาษา Java
}
System.out.println("Writing file complete");
} // end main
}
---------- Java Output----------
Writing file complete
การอานขอมลชนด Primitive จาก Binary File โปรแกรม ReadFromBinary.java แสดงการอานขอมลชนด Primitive จาก Binary File โดยใชขอมลจากแฟมขอมล ‚output.data‛ ซงไดมาจากโปรแกรม WriteToBinary.java
ในคลาส DataInputStream ม Method ทใชในการอานขอมลชนด Integer โดยใช Method readInt() หรอถาตองการใหอานขอมลชนด Double ใช Method readDouble() ดงนน การบนทกขอมลใชคลาส DataOutputStream และการอานขอมลตองใชค าสงทสอดคลองกบขอมลทบนทกดวย เชน ถาบนทกขอมลเปน Integer โดยใช writeInt() เวลาอานขอมลควรใชค าสง readInt() import java.io.*;
public class ReadFromBinary {
public static void main(String[] args) {
try {
DataInputStream input = new DataInputStream (
new FileInputStream ("output.dat"));
for(int i=0; i<10; i++) {
// อานขอมลชนด Integer System.out.println( input.readInt() );
}
}
catch (FileNotFoundException e) {
System.out.println("Error, cannot create the file");
System.exit(1);
}
catch (IOException e) {
System.out.println("Error while reading the file");
System.exit(1);
}
} // จบ main
}
---------- Java Output----------
0
1
2
3
4
5
6
7
8
9
การเขยนโปรแกรมภาษา Java 171
โปรแกรม ReadFromBinary.java แสดงการอานขอมลโดยททราบจ านวนขอมลลวงหนา ดงนนสามารถใช for(int i=0; i<10; i++) ไดทนท แตถาไมทราบจ านวนขอมล สามารถใช Method ชอ available() ไดดงตวอยาง while(input.available() != 0 ) {
input.readInt();
}
Method available() จะสงจ านวนขอมลทเหลออย ในกรณทไมมขอมลในแฟมขอมลแลว available() จะสงคา 0 กลบ ดงนนผเขยนโปรแกรมใช while Loop ในการตรวจสอบคาได New File I/O ส าหรบ Java SDK version 1.4 หรอใหมกวา ผพฒนาภาษา Java ไดมการออกแบบ Package ใหมชอ java.nio และ java.nio.channels ซง Package Java New I/O มความสามารถเหนอกวาการอานเขยนขอมลโดยใช Stream ใน java.io แบบเดม ใน Package java.nio รวมค าสงทใชในการสราง Buffer เพอเกบขอมลส าหรบเขยนลงแฟมขอมลหรอใชเกบขอมลทอานมาจากอปกรณน าเขาดงภาพท 10.1 การเขยนขอมลไปทแฟมขอมลโดยใช Java New I/O จ าเปนตองใชคลาสและขนตอนดงตอไปน
1. ใชคลาส File ในการสราง Path และชอของแฟมขอมล รวมถงใชในการทดสอบวาแฟมขอมลสามารถเขยนไดซงปองกนไมใหเขยนทบแฟมขอมลทมอยแลว
2. ใชคลาส FileOutputSteam ในการสราง Stream ไปทแฟมขอมลเพอใชในการเขยน โดย Parameter ใน Constructor ของ FileOutputStream เปนวตถ File
3. ใชคลาส ByteBuffer ซงอยใน Package java.nio ในการเตรยมขอมลส าหรบเขยนไปทแฟมขอมล
4. ใชคลาส FileChannel ใน Package java.nio.channels เชอมตอกบแฟมขอมล เนองจาก ByteBuffer ไมสามารถเชอมตอกบแฟมขอมลไดโดยตรงจงจ าเปนตองอาศย FileChannel ใชเปนทางเชอมตอระหวาง ByteBuffer กบ FileOutputStream
ภาพท 10.1 แสดงการอานเขยนขอมลโดยใช Buffer เรมตนใชวตถ File เพอสรางชอของแฟมขอมลกอน รวมถงการตรวจสอบวาแฟมขอมลนสามารถอานได หลกจากนนสรางวตถ FileOutputStream เพอเปน Stream ทตดตอกบแฟมขอมล โดย Constructor ของ FileOutputStream เปนวตถจากคลาส File ทสรางขนไวแลวตอนแรก เมอไดวตถ FileOutputStream แลว จงสราง FileChannel โดยใช Method ของ FileOutputStream ทชอ getChannel() เมอไดวตถ FileChannel แลว ขนตอน
Write
Read Disk Buffer
172 การเขยนโปรแกรมภาษา Java
ตอไปสรางวตถ ByteBuffer เพอใชในการเตรยมขอมลทตองการเขยน สวนวธการเขยนใช Method ของ FileChannel ชอ write(ByteBuffer buf)
ภาพท 10.2 แสดงความสมพนธของคลาสทใชในการอานแฟมขอมล ภาพท 10.2 แสดงความส าพนธระหวางคลาสตางๆ ใน Package java.io, java.nio และ java.nio.channels การเขยนขอมลไปทแฟมขอมลตองเตรยมขอมลทตองการเขยนไวท ByteBuffer ดงนนผอานตองเขาใจการใชงานคลาส ByteBuffer กอนวามเรยกใชงานไดอยางไร ByteBuffer การเขยนขอมล จ าเปนตองเตรยม Buffer เปนทเกบขอมลส าหรบการเขยนขนกอน โดยใชคลาส ByteBuffer ซงคลาสนเปน Abstract Class ท าใหไมสามารถสรางวตถไดโดยตรงจากคลาส ByteBuffer แตใชการเรยก Static Method ทชอ allocate() ในคลาส ByteBuffer แทน เพอท าการสรางวตถจาก ByteBuffer ไดดงตวอยาง ByteBuffer buf = ByteBuffer.allocate(1024);
ตวเลข 1024 หมายถงการจองหนวยความจ าขนาด 1024 ไบต (ซงคานไมสามารถเปลยนแปลงไดหลงจาก
มการก าหนดคาแลว) ใหกบตวแปร buf โดยมโครงสรางของ ByteBuffer ดงภาพท 10.3 ซงมตวแปรทเกยวของ 3 ตวคอ
1. capacity คอคาสงสดของหนวยความจ าทจองไว คา capacity ไมสามารถเปลยนได 2. position ต าแหนงเรมตนทเขยนหรออานขอมลจาก ByteBuffer 3. limit ต าแหนงแรกทไมมการเขยนหรออานขอมล ดงนนต าแหนง limit -1 เปนต าแหนงสนสดการ
เขยนหรออานขอมลจาก ByteBuffer
จากรป 10.3 การอานหรอเขยนขอมลจาก ByteBuffer เรมตนจากต าแหนง position จนไปถงต าแหนงท limit-1 ดงนน หรอเรมตนการเขยนขอมลจากต าแหนงท 0 จนไปถงต าแหนงท 1020 รวมเปนจ านวน 1021 ไบต (limit มคาเทากบจ านวนไบตทสามารถเขยนได)
File(แฟมขอมล) FileChannel
ByteBuffer
FileOutputStream
write()
การเขยนโปรแกรมภาษา Java 173
ภาพท 10.3 แสดงโครงสรางของ ByteBuffer
ผเขยนโปรแกรมสามารถอานหรอเขยนขอมลไปท ByteBuffer ต าแหนงใดกได โดยระบคาของ position ในต าแหนงทตองการ เชน position เทากบ 3 หมายถงเรมขยนขอมลต าแหนงท 3 ส าหรบคา position และ limit สามารถเปลยนแปลงได โดยมกฎวา คา position ตองมคานอยหรอเทากบคา limit และคา limit ตองมคานอยกวาหรอเทากบคา capacity ดงสมการตอไปน
capacitylimitposition0
คลาส ByteBuffer มการ Inherit มาจากคลาส Buffer ดงนนสามารถใช Methods ของคลาส Buffer ไดดวย เชน Method ทใชในการตงคา position และ limit
Buffer position(int newPosition) Buffer limit(int newLimit)
Method ทงสองสงคากลบเปน Buffer ซงท าใหสามารถการเรยกใช Method แบบตอเนองไดในค าสงเดยวกน ดงตวอยางตอไปน ByteBuffer buf = ByteBuffer.allocate(1024);
buf.position(100).limit(512);
การใชค าสง buf.position(100) เปนการตงคาให position มคาเปน 100 และคาทสงกลบเปน Buffer ท าใหสามารถเรยกใช Method limit(512) ตอเนองไดทนท ในกรณทมการตงคาให position มคามากกวาคา limit จะมการสง Exception ทชอ IllegalArgumentException ออกมา ในกรณทตองการทราบคา position, limit และ capacity สามารถเรยกใชงาน Method ตอไปน
int position() int limit() int capacity()
capacity = 1024
position = 0 limit = 1021
174 การเขยนโปรแกรมภาษา Java
ส าหรบ Method int position() และ int limit() ซงมลกษณะการเขยนคลายกบ Method Buffer postion(newPosition) และ Buffer limit(newLimit) แต Method ทงสามเพยงสงคากลบเปนคาของตวแปร position, limit และ capacity ตามล าดบ ไมไดมการตงคาตวแปรใดๆ ในคลาส ByteBuffer โปรแกรม TestBuffer.java แสดงวธการใช Method postion(), limit() และ capcity() import java.nio.*;
public class TestBuffer {
public static void main(String[] args) {
ByteBuffer buf = ByteBuffer.allocate(1024);
System.out.println("position is " + buf.position() );
System.out.println("limit is " + buf.limit() );
System.out.println("capacity is " + buf.capacity() );
// ตงคา position และ limit buf.position(100).limit(512);
System.out.println("\nAfter call buf.position(100).limit(512);");
System.out.println("position is " + buf.position() );
System.out.println("limit is " + buf.limit() );
System.out.println("capacity is " + buf.capacity() );
}
}
---------- Java Output----------
position is 0
limit is 1024
capacity is 1024
After call buf.position(100).limit(512);
position is 100
limit is 512
capacity is 1024
จากโปรแกรม TestBuffer.java เรมตนเมอสราง ByteBuffer คา position มคาเทากบ 0 และคา limit มคาเทากบ capacity เสมอคอ 1024 ส าหรบ Method ตอไปคอ
Buffer clear()
วตถ ByteBuffer ทใชไปแลวสามารถน ามาใชใหมไดโดยใช Method clear() ซงท าหนาทปรบคาตวแปร position และ limit ใหเปนคาเรมตน หลงจากเรยกใชค าสง clear() ท าใหคา position กลบไปเทากบ 0 และ limit เทากบ capacity นนเอง ไมไดลบขอมลใน ByteBuffer ทงแตอยางไร โปรแกรม TestClearBuffer.java แสดงวธการใชงาน Method clear() import java.nio.*;
public class TestClearBuffer {
public static void main(String[] args) {
ByteBuffer buf = ByteBuffer.allocate(1024);
showAll(buf);
การเขยนโปรแกรมภาษา Java 175
// ตงคา position และ limit buf.position(100).limit(512);
System.out.println("\nAfter call buf.position(100).limit(512);");
showAll(buf);
// ตงคา position และ limit ใหเปนคาเรมตน buf.clear();
System.out.println("\nAfter call buf.clear()");
showAll(buf);
}
public static void showAll(ByteBuffer buf) {
System.out.println("position is " + buf.position() );
System.out.println("limit is " + buf.limit() );
System.out.println("capacity is " + buf.capacity() );
}
}
---------- Java Output----------
position is 0
limit is 1024
capacity is 1024
After call buf.position(100).limit(512);
position is 100
limit is 512
capacity is 1024
After call buf.clear()
position is 0
limit is 1024
capacity is 1024
Buffer flip() Buffer rewind() int remaining()
Method flip() ท าใหคา limit เทากบ position ในปจจบน และ คา position เทากบ 0 โดยทวไปการเขยนขอมลไปท ByteBuffer ใชค าสง put(byte b) เชน buf.put( (byte) 1 ); จะท าใหคา position เพมอกหนงดวย ดงนนเมอมการเขยนขอมลไปท ByteBuffer จะท าใหคา position เปลยนไปเปนจ านวนเทากบจ านวนขอมลทถกเขยนลงไป เมอเตรยมขอมลใน ByteBuffer เรยบรอยแลว และตองการเขยนขอมลทอยใน ByteBuffer ไปทแฟมขอมลโดยผานวตถ FileChannel จ าเปนตองตงคาให limit เทากบ position กอน และ ใหคา position เทากบ 0 เสมอ เพอใหสะดวกในการเขยนค าสง ผเขยนโปรแกรมสามารถใช filp() แทนได ดงภาพท 10.4 Method Buffer rewind() ท าใหคา position เทากบ 0 สวนคา limit จะไมเปลยนแปลง Method นใชในกรณทตองการอานขอมลจาก ByteBuffer หลายครง หรอตองการเขยนขอมลเดมไปทแฟมขอมลหลายแฟมขอมล และไมตองการใช ByteBuffer จ านวนมาก สามารถน า ByteBuffer ทมอยแลวมาใชใหมไดโดยใชค าสง rewind()
176 การเขยนโปรแกรมภาษา Java
ค าสง remaining() สงคากลบเปน limit() – position() หมายถงจ านวน ByteBuffer ทสามารถอานหรอเขยนไดมจ านวนเทาไร สวน Method ในสวนสดทายคอ
หลงจากเขยนขอมล 100 ไบต คา position จะเทากบ 100
ถาตองการเขยนขอมล 100 ไบตไปทแฟมขอมล จะเปนตองใชค าสง flip() เพอตงคาให limit เทากบ 100 และ position เทากบ 0 กอน หลงจากเรยก Method flip()
ภาพท 10.4 แสดงการท างานของค าสง flip()
ByteBuffer duplicate(); ByteBuffer slice();
ผเขยนโปรแกรมสามารถท าส าเนา ByteBuffer ได 2 วธคอใช 1) Method ByteBuffer duplicate() และ 2) ByteBuffer slice() ซงมความแตกตางคอ การใช duplicate() ไมไดเปนการสราง ByteBuffer ใหม แตเปนการสรางตวแปรใหชไปทหนวยความจ าในต าแหนงเดยวกน โดยม position และ limit แยกกน ดงนนถามการเปลยนแปลงขอมลในหนวยความจ าส าหรบ ByteBuffer เดมจะท าใหสงผลกระทบตอวตถ ByteBuffer ทใชงานอย เพราะใชหนวยความจ าทเดยวกน ดงภาพท 10.5
capacity = 1024
position = 0 limit = 1021
capacity = 1024
position = 100 limit = 1021
capacity = 1024
position = 0 limit = 100
การเขยนโปรแกรมภาษา Java 177
สวนค าสง slice() มการท างานคลายกบค าสง duplicate() ซงเปนการใช ByteBuffer รวมกน แตเปนการสราง ByteBuffer ใหมซงมขนาดเทากบ position จนไปถงต าแหนง limit -1 ของ ByteBuffer เดม ค าสง slice() เปนการสรางทางเดนใหมใหผเขยนโปรแกรมสามารถอางถง ByteBuffer ในมมมองใหม
ByteBuffer buf = ByteBuffer.allocate(10); buf.position(3).limit(7); ByteBuffer newBuf = buf.duplicate();
ByteBuffer newBuf1 = buf.slice();
ภาพท 10.5 แสดงการใช duplicate() และ slice()
การสราง View จาก ByteBuffer บางครงการอานและเขยนขอมล ไมมความจ าเปนตองอยในรปของ Byte เสมอไป ขอมลอาจเปน Integer หรอ Short ได ดงนนเพอชวยอ านวยความสะดวกในการเขยนโปรแกรม ภาษา Java อนญาตใหผเขยนโปรแกรมสามารถสราง View จาก ByteBuffer ไปเปน Buffer ชนดอนได โดยใช Method ตอไปน
capacity=10
position = 3 limit = 7
capacity=10
buf.position = 3 newBuf.position = 3
buf.limit = 7 newBuf.limit = 7
buf
buf
newBuf
capacity=10
position = 3
limit = 7
buf newBuf1
position = 0
limit = 4
slice() ไมไดสราง ByteBuffer ขนใหมแตเปนการใช ByteBuffer บางสวนรวมกน
178 การเขยนโปรแกรมภาษา Java
CharBuffer asCharBuffer(); ............................ Buffer ชนดตวอกษร DoubleBuffer asDoubleBuffer(); ..................... Buffer ชนด Double FloatBuffer asFloatBuffer(); ........................... Buffer ชนด Float IntBuffer asIntBuffer(); ................................... Buffer ชนด Integer LongBuffer asLongBuffer(); ........................... Buffer ชนด Long ShortBuffer asShortBuffer(); .......................... Buffer ชนด Short
การสราง View ไมไดเปนการสราง Buffer ใหม แตเปนการสรางมมมองขอมลแบบ ByteBuffer ใหเปนขอมลตาม View ทสรางขน การสราง View มประโยชนส าหรบการเขยนขอมลหลายชนดลงไปท ByteBuffer และเขยนขอมลทเปน Array ไปท ByteBuffer ตวอยางการสราง View ทเปน Integer เชน ByteBuffer buf = ByteBuffer.allocate(10);
IntBuffer intBuf = buf.asIntBuffer();
ภาพท 10.6 การสราง View IntBuffer จาก ByteBuffer
จากรป 10.6 คา position, limit และ capacity ของ intBuf ไมตรงกบคาของ buf เพราะ IntBuffer ตองการ 4 ไบตส าหรบขอมล 1 ตว ดงนนจากเดม buf ม capacity เทากบ 10 ซงหารดวย 4 มคาเทากบ 2 ท าใหสามารถเกบขอมลทเปน Integer ไดเพยง 2 คาเทานน การสราง View ใหม มความสมพนธกบคา position และ limit ท ByteBuffer ในปจจบนดวย กลาวคอการสราง Veiw จะเรมจากต าแหนง position จงถง limit-1 จากตวอยางถา position ของ buf มคาเทากบ 5 จะท าใหสราง View IntBuffer ทสามารถบรรจคา Integer ไดเพยงคาเดยวเทานน ผเขยนโปรแกรมสามารถสราง View โดยตรงจาก allocate() เชน LongBuffer longBuf = LongBuffer.allocate(1024);
capacity=10
position = 0
limit = 10 buf
capacity=2
position = 0
limit = 2 intBuf
การสราง View ไมไดสราง Buffer ขนใหมแตเปนการสรางมมมองใหใหกบ ByteBuffer หมายความวาถามการเปลยนขอมลใน View จะท าใหขอมลใน ByteBuffer เปลยนตามดวย
การเขยนโปรแกรมภาษา Java 179
เนองจากการเขยนขอมลโดย FileChannel รบ Parameter ทเปน ByteBuffer เทานน ถามการสราง View โดยตรงแลว การเปลยนขอมลจาก View เปน ByteBuffer เพอใชกบ FileChannel มความซบซอน เพอใหเขยนโปรแกรมงายขน ควรสราง ByteBuffer กอน แลวจงสราง View ทตองการจาก ByteBuffer อกครงหนง การสราง ByteBuffer โดยใชขอมลจาก Array ByteBuffer สามารถสรางจาก Array ไดโดยใชค าสง ByteBuffer wrap(byte[] array) ซงจะเปลยนให Array เปน ByteBuffer แตไมไดสราง ByteBuffer ขนใหม ดงนนถามการแกไขขอมลใน ByteBuffer จะท าใหขอมลใน Array เปลยนตามไปดวย โปรแกรม ArraytoByteBuffer.java แสดงวธการใช Method wrap() import java.nio.*;
public class ArraytoByteBuffer {
public static void main(String[] args) {
String s = "Hello, how are you today?";
// เปลยน String ไปเปน byte[] byte[] b = s.getBytes() ;
// สราง ByteBuffer จาก Array b ByteBuffer buf = ByteBuffer.wrap( b );
// ดงขอมลจาก buf กลบไปเปน Array out byte[] out = buf.array();
System.out.println( new String(out) );
}
}
---------- Java Output----------
Hello, how are you today?
จากโปรแกรม ArraytoByteBuffer.java ค าสง array() มการสงคากลบเปน Array ของ byte และไมสามารถแสดงผลโดยใชค าสง System.out.println() ไดโดยตรง จงใชคลาส String ชวยเปลยนให byte[] เปน String จงสามารถแสดงผลลพธทางจอภาพได การเขยนขอมลไปท ByteBuffer การเขยนขอมลไปท ByteBuffer ม 2 วธ คอ การเขยนขอมลแบบ Relative และ Absolute การเขยนขอมลแบบ Relative จะเรมเขยนตรงกบต าแหนง position และท าใหคา position มการเพมขนเทากบจ านวนขอมลทเขยนไป สวนการเขยนขอมลแบบ Absolute เปนการระบต าแหนงทตองการเขยนโดยไมตองใชคา position ท าใหคา position ไมมการเปลยนแปลง แตไมสามารถระบต าแหนงทตองการเขยนเกนต าแหนง limit-1 ได Method ทใชในการเขยนขอมลไปท ByteBuffer แบบ Relative คอ
ByteBuffer put(byte b); เขยนขอมลไปท ByteBuffer ครงละ 1 ไบต คา position เพมอก 1
180 การเขยนโปรแกรมภาษา Java
ByteBuffer put(byte[] src); เขยนขอมล Array ของ src ทงหมดไปท ByteBuffer คา position เพมเปนจ านวน src.length
ByteBuffer put(byte[] src, int offset, int length); เขยน Array ของ src โดยเรมท src[offset] จนไปถง src[offset + length -1] และท าใหคา
position เพมขนเทากบ length ดวย ByteBuffer put(ByteBuffer src)
น าขอมลจาก src ซงเปนชนด ByteBuffer โดยเรมตนจากต าแหนง src.position จนไปถง src.limit-1 เขยนไปท ByteBuffer
Method ทใชในการเขยนขอมลไปท ByteBuffer แบบ Absolute มเพยง Method เดยว คอ
ByteBuffer put(int index, byte b) เขยนขอมล b ไปท ByteBuffer ต าแหนง index และคา position ไมเปลยนแปลง การเขยนขอมล
แบบ Absolute สวนใหญใชในการแกไขขอมลใน ByteBuffer ในกรณททราบต าแหนง
การเขยนขอมลชนด Byte ไปทแฟมขอมล การเขยนขอมลชนด Byte ไปทแฟมขอมลสามารถใชคลาส ByteBuffer ไดทนทโดยไมจ าเปนตองสราง View และเมอเสรจการเตรยมขอมลใน ByteBuffer แลว กอนทจะเขยนขอมลลงแฟมขอมล ตองเรยกใชค าสง flip() ดงทกลาวแลวในตอนตนดวย เพอใหต าแหนง position กลบไปท 0 กอน โปรแกรม WriteByteToFile.java แสดงการเขยนขอมลชนด Byte ไปทแฟมขอมลชอ ‚data1.dat‛ import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class WriteByteToFile {
public static void main(String[] args) {
byte[] b = {0,1,2,3,4,5,6,7,8,9};
// สราง ByteBuffer โดยมขนาดเทากบ b.length ByteBuffer buf = ByteBuffer.allocate(b.length);
// เขยน Array b ไปท ByteBuffer buf.put(b);
// เมอเขยนเสรจแลวตองเรยกค าสง flip() ดวย buf.flip();
// สรางวตถ File File f = new File("data1.dat");
// ตรวจสอบวา data1.dat ไมไดถกสรางกอนหนาน if ( f.exists() ){
การเขยนโปรแกรมภาษา Java 181
System.out.println("Cannot write. data1.dat exists.");
System.exit(1);
}
FileOutputStream fos = null;
try{
// สราง FileOutputStream โดยม Paramter เปน File fos = new FileOutputStream(f);
}
catch (FileNotFoundException e) {
// แสดง Error ถาผดพลาด
e.printStackTrace(System.err); }
// สราง FileChannel เปนทางเชอมตอระหวางแฟมขอมลและ ByteBuffer FileChannel fc = fos.getChannel();
try {
fc.write(buf); // เขยนขอมลไปท ByteBuffer ผานทางวตถ FileChannel fc.close(); // ปดวตถ FileChannel fos.close(); // ปดวตถ FileOutputStream
}
catch (IOException e) {
e.printStackTrace(System.err);
}
System.out.println("data1.dat has been written successfully");
}
}
---------- Java Output----------
data1.dat has been written successfully
การเขยนขอมลชนด Array ไปทแฟมขอมล การเขยนขอมล Array ของ Short, Integer, Long, Float, Double หรอ Character ไปทแฟมขอมล ควรมการสราง View เพอใชเขยนขอมลตามชนดตางๆ ทตองการ เพราะใน View มค าสง put() ทเปลยนขอมลจาก Array ไปเปน Buffer ได เชนคลาส DoubleBuffer มค าสง put(double[] src) หรอ คลาส LongBuffer มค าสง put(long[] src) เชนกน การสราง View สงผลใหตวแปร position และ limit แยกจาก ByteBuffer ดงนนการเขยนขอมลไปท View แบบ Relative จะท าใหคา position ของ View นนเปลยนไป แตคา position ของ ByteBuffer นนคงเดม ดงนนเมอเขยนขอมลไปทแฟมขอมล ตองท าการปรบคา limit ของ ByteBuffer ใหมคาเทากบคา position ของ View x ขนาดของขอมล (เชนถาเปน Long ตองคณดวย 8) และคา position ของ ByteBuffer ใหมคาเปน 0 กอนเขยนขอมลไปทแฟมขอมล ตวอยางตอไปแสดงถงขนตอนการเขยนขอมลชนดอนทไมใช Byte // สราง ByteBuffer ขนาด 800 ByteBuffer buf = ByteBuffer.allocate(800);
182 การเขยนโปรแกรมภาษา Java
/* สราง View ทเปนชนด Long จาก ByteBuffer ท าให LongBuffer ม position เปน 0 และ limit เทากบ 100 หรอเทากบ capacity เพราะขอมลชนด Long มขนาด 8 ไบต */ LongBuffer longBuf = buf.asLongBuffer();
long[] data = {1L, 2L, 3L, 4L, 5L};
longBuf.put(data);
/* หลงจากค าสง put() ท าใหคา position ของ longBuf เปน 5 และ limit เปน 100 เทาเดม ถาตองการเขยนขอมลไปทแฟมขอมลโดยใช FileChannel ตองปรบคา position ของ buf ใหเทากบ position ของ longBuf กอน แลวจงใช filp() เพอปรบให position ของ buf เปน 0 และ limit ของ buf เทากบ position */ /* คา position ของ longBuf เปลยนไป 1 ท าใหคา position ของ buf เปลยนไป 8 เพราะ Long มขนาด 8 ไบต จงตองคณดวย 8 */ buf.position( longBuf.position() * 8 );
// ปรบคา position และ limit เพอการเขยนไปทแฟมขอมลโดยใช FileChannel buf.flip();
โปรแกรม WriteArrayToFile.java แสดงการเขยนขอมล Array ชนด Long ไปทแฟมขอมลชอ data2.dat import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class WriteArrayToFile {
public static void main(String[] args) {
long[] data = {0L,1L,2L,3L,4L,5L,6L,7L,8L,9L};
// สราง ByteBuffer ขนาด 800 ไบต ByteBuffer buf = ByteBuffer.allocate(800);
// สราง Long View จาก ByteBuffer LongBuffer longBuf = buf.asLongBuffer();
// เขยนขอมลของ Array long[] ไปท Long View longBuf.put(data);
// ปรบคา buf.position = longBuf.position * 8 buf.position( longBuf.position() * 8 );
// ตงคา limit ใหเทากบ current position และคา position ใหเทากบศนย buf.flip();
File f = new File("data2.dat");
if ( f.exists() ) {
System.out.println("Cannot write. data1.dat exists.");
System.exit(1);
}
FileOutputStream fos = null;
การเขยนโปรแกรมภาษา Java 183
try{
// สราง FileOutputStream fos = new FileOutputStream(f);
}
catch (FileNotFoundException e) {
// ในกรณทมความผดพลาดใหแสดงออกทาง Standard Error e.printStackTrace(System.err); }
FileChannel fc = fos.getChannel(); // สราง FileChannel try {
fc.write(buf); // เขยนขอมลจากวตถ ByteBuffer ไปทแฟมขอมล
fc.close(); // ปดวตถ FileChannel
fos.close(); // ปดวตถ FileInputStream
}
catch (IOException e) {
e.printStackTrace(System.err);
}
System.out.println("data2.dat has been written successfully");
}
}
---------- Java Output----------
data2.dat has been written successfully
การเขยนขอมล String ไปทแฟมขอมล การเขยนขอมลชนด String สามารถเขยนได 2 วธคอ แบบ ASCII และ Unicode การเขยนแบบ ASCII สามารถใชค าสง byte[] getBytes() ในคลาส String เพอเปลยนใหขอมล String เปน ASCII (ตวอยางอยในโปรแกรม ArraytoByteBuffer.java ทผานมา) สวนการเขยนขอมลแบบ Unicode ใชการสราง View ของ Character คลายการสราง View ของ Long โปรแกรม StringToFile1.java และ StringToFile2.java แสดงวธการเขยนขอมล String ไปทแฟมขอมลแบบ ASCII และ Unicode ตามล าดบ // เขยน ASCII ไปท output1.txt import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class StringToFile1 {
public static void main(String[] args) {
String data = "This data is used for testing. “ +
“The program will write data to output1.txt\n" +
“After writing, you can open output1.txt by text editor";
// สราง ByteBuffer โดยมขนาดเทากบ data.length() ByteBuffer buf = ByteBuffer.allocate( data.length() );
// ใชค าสง getBytes() เพอเปลยน String ใหเปน Array byte[] byte[] raw_data = data.getBytes();
184 การเขยนโปรแกรมภาษา Java
// ใสขอมลไปท ByteBuffer และเรยก flip() เพอเตรยมเขยนขอมลลงแฟมขอมล
buf.put(raw_data).flip();
File f = new File("output1.txt");
FileOutputStream fos =null;
try{
// สรางวตถ FileOutputStream fos = new FileOutputStream(f);
}
catch (FileNotFoundException e) {
e.printStackTrace(System.err);
}
// สรางวตถ FileChannel FileChannel fc = fos.getChannel();
try {
// เขยนขอมลจาก ByteBuffer ไปทแฟมขอมล fc.write(buf);
fc.close();
fos.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
}
System.out.println("output1.txt has been written successfully");
}
}
---------- Java Output----------
Outpu1.txt has been written successfully
ผลลพธจากโปรแกรม StringToFile2.java คอแฟมขอมลชอ output2.txt โดยมขอมลเปนชนด Unicode ในโปรแกรมนมการแสดงวธการใชค าสง size() ในคลาส FileChannel เพอหาขนาดของแฟมขอมล ซงค าสงนตองอยกอนค าสง close() เสมอ // เขยนตวอกษร Unicode ไปท output2.txt
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class StringToFile2 { public static void main(String[] args) {
String data = "This data is used for testing. “ +
“The program will write data to output2.txt\n" +
"After writing, you cannot open output2.txt by text editor";
/* สราง ByteBuffer โดยมขนาดเทากบ data.length() * 2 เนองจาก 1 ตวอกษร Unicode มขนาด 2 ไบต */ ByteBuffer buf = ByteBuffer.allocate( data.length()* 2 );
CharBuffer charBuf = buf.asCharBuffer();
การเขยนโปรแกรมภาษา Java 185
// เขยนขอมลชนด String ไปท ByteBuffer charBuf.put(data);
// ปรบคา position และเรยกค าสง filp() buf.position( charBuf.position() *2 ).flip();
File f = new File("output2.txt");
FileOutputStream fos =null;
try{
// สรางวตถ FileOutputStream fos = new FileOutputStream(f);
}
catch (FileNotFoundException e) {
e.printStackTrace(System.err);
}
// สรางวตถ FileChannel FileChannel fc = fos.getChannel();
long file_size=0;
try {
// เขยนขอมลจาก ByteBuffer ไปทแฟมขอมล
fc.write(buf);
// ค าสง size() ใชหาขนาดของแฟมขอมลทถกเขยน file_size = fc.size();
fc.close();
fos.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
}
System.out.println("output2.txt has been written successfully");
System.out.println("File size is "+ file_size);
}
}
---------- Java Output----------
output2.txt has been written successfully
File size is 282
การเขยนขอมลหลายชนดลงแฟมขอมลเดยวกน การเขยนขอมลหลายชนดไปทแฟมขอมลเดยวกน สามารถท าไดโดยใช Method ในคลาส ByteBuffer ซงขนตนดวย put มทงสน 6 Method คอ
ByteBuffer putChar(char value) ByteBuffer putDouble(double value) ByteBuffer putFloat(float value) ByteBuffer putInt(int value)
186 การเขยนโปรแกรมภาษา Java
ByteBuffer putLong(long value) ByteBuffer putShort(short value)
ตวอยางเชนการเกบ String ทมความยาวไมเทากนไวในแฟมขอมลเดยวกน โดยใชโครงสรางขอมลซงประกอบดวย ขอมล 4 ไบตแรกเปนจ านวนตวอกษร ตามดวยขอมลตวอกษร และถดไปเปนขอมลชดท 2 ชดท 3 ตอเนองไปจนครบชดท N
โปรแกรม StringToFile3.java แสดงวธการเขยนเขยนบทสนทนาภาษาองกฤษอง A และ B โดยทแตละประโยคมขนาดไมเทากน โดยใชรปแบบการเกบขอมลดงทกลาวไปแลว
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class StringToFile3 {
public static void main(String[] args) {
String[] data = { "A: Hello how are you?\n",
"B: I am fine\n",
"B: How about you?\n",
"A: I am ok\n",
"B: See you at java course, bye"};
// หาจ านวนตวอกษรทงหมดในตวแปร data int size = 0;
for(int i=0; i < data.length; i++)
size += data[i].length();
/* สราง ByteBuffer โดยมขนาดเทากบจ านวนบรรทดของบทสนทนา x 4 เนองจากในทก Record ตองเกบจ านวนตวอกษร (Length of String) ใน 1 บรรทดของบทสนทนา เปนตวแปรชนด Integer ซงมขนาดเปน 4 ไบต และบวกดวยจ านวนตวอกษรทงหมด (String data) */ ByteBuffer buf = ByteBuffer.allocate( data.length*4 + size );
// เขยน String ไปท ByteBuffer for(int i=0; i<data.length; i++){
byte[] raw_data = data[i].getBytes();
buf.putInt( data[i].length() );
buf.put(raw_data);
}
Length of String (int) String data (String) Length of String (int) String data (String) ...
ชดท 1 ชดท N
5 abcde 3 abc
ตวอยางการเกบขอมล abcde abc คา data.length มคาเทากบ 2 จ านวนไบตทงหมดทตองจองคอ 2 x 4 + 8 = 16
การเขยนโปรแกรมภาษา Java 187
// ใชค าสง flip() เพอเตรยมเขยนขอมลลงแฟมขอมล buf.flip();
File f = new File("output3.dat");
FileOutputStream fos =null;
try{
fos = new FileOutputStream(f);
}
catch (FileNotFoundException e) {
e.printStackTrace(System.err);
}
FileChannel fc = fos.getChannel();
long filesize = 0;
try {
fc.write(buf);
filesize = fc.size();
fc.close();
fos.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
}
System.out.println("output3.dat has been written successfully");
System.out.println(filesize + " bytes");
}
}
---------- Java Output----------
output3.dat has been written successfully
114 bytes
การอานขอมลจากแฟมขอมลโดยใช Java New I/O การอานขอมลจากแฟมขอมลโดยใช Java New I/O มขนตอนการเขยนโปรแกรมคลายกบการเขยนขอมลไปทแฟมขอมล แตมความแตกตางกนคอ การอานขอมลตองใชคลาส FileInputStream แทน FileOutputStream และเปลยนมาใช Method FileChannel.read() แทน FileChannel.write() เนองจากเปนการอานขอมลจากแฟมขอมล โปรแกรม ReadByteFromFile.java แสดงวธการอานขอมลชนด Byte โดยใชขอมลในแฟมขอมล data1.dat และแสดงผลลพธทางจอภาพ ซงแฟมขอมลนถกสรางขนจากโปรแกรม WriteByteToFile.java // ใชแฟมขอมล data1.dat จากโปรแกรม WriteByteToFile.java import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
public class ReadByteFromFile {
public static void main(String[] args) {
File myFile = new File("data1.dat");
// ประกาศตวแปร FileInputStream FileInputStream fis = null;
188 การเขยนโปรแกรมภาษา Java
// สรางวตถ FileInputStream try{
fis = new FileInputStream(myFile);
}
catch (FileNotFoundException e) {
System.out.println("File not found");
System.exit(1);
}
// สรางวตถ FileChannel FileChannel inputChannel = fis.getChannel();
ByteBuffer buf = null;
// ใช try และ catch เนองจาก Method size() ใน FileChannel สามารถ throw IOException try {
/* สราง ByteBuffer เพออานขอมลจาก Channel ใช Method size() เพอหาขนาดของแฟมขอมล */ buf = ByteBuffer.allocate( (int) inputChannel.size() );
// อานขอมลจาก data1.dat ไปท ByteBuffer inputChannel.read(buf);
inputChannel.close();
fis.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
byte[] b = buf.array();
System.out.println("Data from data1.dat are");
// พมพผลลพทธทางจอภาพ for(int i=0; i<b.length; i++) {
System.out.print(b[i] + " ");
}
}
}
---------- Java Output----------
Data from data1.dat are
0 1 2 3 4 5 6 7 8 9 Normal Termination
การอานขอมลชนดอนเชน Long สามารถใชค าสง getLong() ในคลาส ByteBuffer ไดเชนเดยวกน โปรแกรม ReadLongFromFile.java แสดงวธการอานขอมลจากแฟมขอมลชอ data2.dat ทถกสรางจากโปรแกรม WriteArrayToFile.java import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
public class ReadLongFromFile {
public static void main(String[] args) {
การเขยนโปรแกรมภาษา Java 189
File myFile = new File("data2.dat");
FileInputStream fis = null;
try{
fis = new FileInputStream(myFile);
}
catch (FileNotFoundException e) {
System.out.println("File not found");
System.exit(1);
}
// สราง FileChannel
FileChannel inputChannel = fis.getChannel();
ByteBuffer buf = null;
try {
buf = ByteBuffer.allocate( (int) inputChannel.size() );
inputChannel.read(buf);
inputChannel.close();
fis.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
// ใช flip() เพอเตรยมการอานขอมลจาก Buffer buf.flip();
System.out.println("Data from data2.dat are");
// ใช for Loop พมพผลลพธทางจอภาพ for(int i=0; i < buf.limit()/8; i++) {
// Method getLong() สงคาใน Buffer เปนชนด Long System.out.print( buf.getLong() + " ");
}
}
}
---------- Java ----------
Data from data2.dat are 0 1 2 3 4 5 6 7 8 9
สวนการอาน String จากแฟมขอมล ท าไดโดยใช Method getChar() ของคลาส ByteBuffer โปรแกรม ReadCharFromFile.java แสดงการอานขอมลตวอกษรชนด ASCII จากแฟมขอมล output1.txt จากโปรแกรม StringToFile1.java import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
public class ReadCharFromFile {
public static void main(String[] args) {
File myFile = new File("output1.txt");
FileInputStream fis = null;
try{
fis = new FileInputStream(myFile);
190 การเขยนโปรแกรมภาษา Java
}
catch (FileNotFoundException e) {
System.out.println("File not found");
System.exit(1);
}
FileChannel inputChannel = fis.getChannel();
ByteBuffer buf = null;
try {
buf = ByteBuffer.allocate( (int) inputChannel.size() );
inputChannel.read(buf);
inputChannel.close();
fis.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
buf.flip();
System.out.println("Data from output1.txt are");
for(int i=0; i < buf.limit(); i++) {
System.out.print( (char)buf.get() );
}
}
}
---------- Java Output----------
Data from output1.txt are
This data is used for testing. The program will write data to output1.txt
After writing, you can open output1.txt by text editor.
การอานขอมลทมหลายชนดในแฟมขอมลเดยว โดยใชผลลพธจากโปรแกรม WriteStringToFile3.java ทไดสรางแฟมขอมลชอ output3.dat ซงเกบ String ทมขนาดไมเทากนในแฟมขอมล โปรแกรม ReadMultipleStringFromFile.java แสดงการอานขอมลจากแฟมขอมล output3.dat จากโปรแกรม StringToFile3.java import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
public class ReadMultipleStringFromFile {
public static void main(String[] args) {
File myFile = new File("output3.dat");
FileInputStream fis = null;
try{
fis = new FileInputStream(myFile);
}
catch (FileNotFoundException e) {
System.out.println("File not found");
System.exit(1);
}
FileChannel inputChannel = fis.getChannel();
ByteBuffer buf = null;
try {
buf = ByteBuffer.allocate( (int) inputChannel.size() );
inputChannel.read(buf);
การเขยนโปรแกรมภาษา Java 191
inputChannel.close();
fis.close();
}
catch (IOException e) {
e.printStackTrace(System.err);
System.exit(1);
}
buf.flip();
System.out.println("Data from output3.dat are");
while( buf.position() < buf.capacity() ) {
// อานจ านวนตวอกษรจากสวนแรก int count = buf.getInt();
// พมพขอมลในสวนทสองโดยใช count for(int i=0; i<count; i++) { System.out.print( (char)buf.get() );
}
}
}
}
---------- Java Output----------
Data from output3.dat are
A: Hello how are you?
B: I am fine
B: How about you?
A: I am ok
B: See you at java course, bye
การท าส าเนาแฟมขอมล การท าส าเนาขอมลใช Method ทชอ transferTo() ในคลาส FileChannel ซงถกออกแบบใหใชในการท าส าเนาขอมลโดยเฉพาะ
long transferTo(long position, long count, WritableByteChannel target) throws IOException
การเรยกใชค าสงตองระบคาตางๆ คอ คา position เปนตวก าหนดจดเรมตนการอานขอมลจากตนฉบบ (Source) คา count เปนจ านวนขอมลทตองการใหท าส าเนา สวน target เปนแฟมขอมลปลายทางซงเปน FileChannel การใชค าสง transferTo() ไมไดประกนวาขอมลไดท าส าเนาครบ โดยคาทสงกลบจากค าสงนเปนจ านวนไบตทสามารถท าส าเนาได ดงนนผเขยนโปรแกรมจ าเปนตองเรยกใชค าสง transferTo() หลายครงจนมนใจไดวาขอมลไดท าส าเนาครบแลว ซงอาจใชค าสง while Loop ในการเรยกใชงานได ค าสง transferTo() มการ throw คาดงตอไปน
IllegalArgumentException – ถา position หรอ count มคาตดลบ
5 abcde
192 การเขยนโปรแกรมภาษา Java
NonReadableChannelException – ถา FileChannel ไมสามารถอานได เชนสราง FileChannle จาก FileOutputStream แทนทจะสรางจาก FileInputStream
NonWritableChannelException – ถาไมสามารถเขยน FileChannel ปลายทาง ได ClosedChannelException – ถา FileChannel มการปดไปแลว AsynchronousCloseException – มการปด FileChannel ระหวางการท าส าเนาขอมล ClosedByInterruptException – มการขดจงหวะของ Operating System ท าให FileChannel ปดลง IOException – ถามความผดพลาดอนๆ
ดงนนการเขยนโปรแกรมจ าเปนตองใช try and catch เพราะ Method transferTo() มการ throw IOException โดยตรง สวน Exception อนๆ จะจบหรอไมกได อยางไรกตาม ถาไมจบ Exception เมอเกดความผดพลาดขนจะท าใหโปรแกรมหยดการท างานทนท โปรแกรม CopyFile.java แสดงการใช Method transferTo() ในการท าส าเนาแฟมขอมล โดยผใชงานตองปอนชอแฟมขอมลทตองการท าส าเนาตอนเรมตนโปรแกรมผานทาง Command Line และเมอโปรแกรมท างานเสรจแลว ผลลพธทไดเปนแฟมขอมลทถกท าส าเนา โดยมชอขนตนวา backup และตามดวยชอของแฟมขอมลตนฉบบ import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
public class CopyFile {
public static void main(String[] args) {
// อานชอแฟมขอมลจาก Command Line if(args.length == 0){
System.out.println("Please enter filename
that you want to copy");
System.exit(0);
}
String filename = args[0];
File srcFile = new File(filename);
// ตรวจสอบวามแฟมขอมลตนฉบบจรง if( !srcFile.canRead() ){
System.out.println(filename + " does not exist.");
System.exit(1);
}
FileInputStream inputFile = null ;
FileOutputStream outFile= null ;
try {
// สราง FileInputStream ส าหรบแฟมขอมลตนฉบบ inputFile = new FileInputStream(srcFile);
// สราง FileOutputStream ส าหรบแฟมขอมลปลายทาง outFile = new FileOutputStream("copy of " + srcFile);
การเขยนโปรแกรมภาษา Java 193
}
catch (FileNotFoundException e){
System.out.println("I/O error");
System.exit(1);
}
// สราวตถ FileChannel FileChannel srcChannel = inputFile.getChannel();
FileChannel destChannel = outFile.getChannel();
// เรยกค าสง transferTo() เพอท าส าเนาแฟมขอมล try{
// จ านวนทไบตทท าส าเนาไปแลว
int written = 0;
// ขนาดของแฟมขอมลตนฉบบ long size = srcChannel.size();
// ใช while Loop เพอเขยนขอมล while(written < size) {
written += srcChannel.transferTo(written, size - written, destChannel);
}
// ปดวตถทงหมด srcChannel.close();
destChannel.close();
inputFile.close();
outFile.close();
System.out.println("Copy file complete: backup "+srcFile);
}
catch (IOException e) {
System.out.println("Error while copying the file");
System.exit(1);
}
}
}
---------- Java Output----------
การอานและเขยนในแฟมขอมลเดยวกน การอานและเขยนขอมลในแฟมขอมลเดยวกน สามารถท าไดโดยใชคลาส RandomAccessFile ใน Package java.io แทนการใช FileInputStream และ FileOutputStream โดย Constructor ของ RandomAcessFile คอ
RandomAccessFile(File, file, String mode)
194 การเขยนโปรแกรมภาษา Java
mode คอ ‚rw‛ ส าหรบการอานและเขยนขอมลในแฟมขอมลเดยวกน ดงตวอยางเชน File myFile = new File(“test.dat”);
RandomAccessFile testFile = new RandomAccessFile(myFile, “rw”);
จากตวอยางเปนการเปดแฟมขอมล test.dat ส าหรบการอานและเขยน ตอไปเปนการสราง FileChannel จาก RandomAccessFile FileChannel ioChannel = testFile.getChannel();
เมอได FileChannel แลวผเขยนโปรแกรมสามารถใชงาน FileChannel นเปนทง Input และ Output Channel สวนวธการเขยนหรออานสามารถใชตวอยางการอานและเขยนขอมลขางตนทกลาวไปแลว โดยสามารถใชการ put() และ get() ใน FileChannel ได
การเขยนโปรแกรมภาษา Java 195
สรป ในบทนอธบายวธการอานและเขยนขอมลจากแฟมขอมล ผเขยนโปรแกรมภาษา Java สามารถใชคลาสใน java.io ส าหรบการอานหรอเขยนตามลกษณะของขอมลทมความแตกตางกนได ในกรณทแฟมขอมลเปนชนด Binary ตองใชคลาส FileInputStream และ FileOutputStream ส าหรบในกรณทแฟมขอมลเปนชนด Character ตองใชคลาส FileReader และ FileWriter แตคลาสทง 4 เหมาะส าหรบการอานและเขยนขอมลเปนไบต ถาขอมลอยในรปอน เชน Integer หรอ Character ผเขยนโปรแกรมควรใชคลาสลกของคลาสทง 4 แทน ดงตารางท 10.1 ส าหรบ Java เวอรชน 1.4 ขนไป มการออกแบบ Package ใหมชอ java.nio และ java.nio.channels ซงเปนวธการอานและเขยนขอมลโดยใช Buffer ซงมประสทธภาพมากกวาการอานและเขยนขอมลแบบเดม
196 การเขยนโปรแกรมภาษา Java
แบบฝกหดทายบทท 10
1. อธบายการใชคลาสใน java.io ในการขอมลจากแฟมขอมลครงละ 1 บรรทด 2. Package java.nio และ java.nio.channels มหนาทอะไร 3. อธบายคา position, limit และ capacity ในคลาส Buffer 4. อธบายการใชงานค าสง duplicate(), slice(), rewind() และ clear() ของ Buffer 5. การสราง View มวตถประสงคอะไร
Programming Problems 1. จงเขยนโปรแกรมเพอรบขอมลชนด double จ านวน 10 คา จาก Keyboard และเขยนลงแฟมขอมลชอ
‚output.dat‛ ใหแสดงการเขยนขอมลโดยใชคลาสใน Package javo.io ปกตและแสดงการเขยนโปรแกรมโดยใช Java New I/O ดวย
2. จงเขยนโปรแกรมเพออานขอมลตวเลขชนด double จากแฟมขอมล ‚output.dat‛ จากขอ 1 และเรยกขอมลจากนอยไปหามาก โดยเกบผลลพธทแฟมขอมลเปน Text File ชอ ‚sorted.txt‛ใหแสดงการอานขอมลโดยใชคลาสใน Package javo.io ปกตและแสดงการเขยนโปรแกรมโดยใช Java New I/O ดวย
3. น าผลลพธจากขอท 1 ‚output.dat‛ ท าส าเนาเปน ‚output.dat.bak‛ โดยใช Method transferTo() ดงตวอยางในหนงสอ
4. จงเขยนโปรแกรมท าส าเนาแฟมขอมลโดยรบชอแฟมขอมลตนฉบบ และแฟมขอมลปลายทางผานทาง Command Line ตวอยางการท าส าเนาแฟมขอมลจาก inputfile.txt ไปยง outputfile.txt ดงน
$java CopyFile inputfile.txt outputfile.txt