"สวัสดี! ในบทเรียนวันนี้ เราจะสนทนากันต่อเกี่ยวกับสตรีมอินพุตและเอาต์พุตใน Java ( Java I/O ) นี่ไม่ใช่บทเรียนแรกในหัวข้อนี้ และจะไม่ใช่บทเรียนสุดท้ายอย่างแน่นอน
:) เกิดขึ้น ภาษา Java มีวิธีมากมายในการทำงานกับ I/O มีคลาสไม่กี่คลาสที่ใช้ฟังก์ชันนี้ ดังนั้น เราจึงแบ่งคลาสเหล่านี้ออกเป็นหลายๆ บทเรียน ดังนั้นคุณจะไม่สับสนตั้งแต่เริ่มต้น :) ในอดีต บทเรียนที่เราได้กล่าวถึง
นี่คือลักษณะของการอ่านข้อมูลจากไฟล์โดยใช้

BufferedReader
ตลอดจน คลาสนามธรรม InputStream
และ คลาสย่อยๆ อีกหลายคลาส วัน นี้ OutputStream
เราจะพิจารณาคลาสใหม่ 3 คลาส: FileInputStream
, FileOutputStream
, และ BufferedInputStream
คลาส FileOutputStream
จุดประสงค์หลักของFileOutputStream
คลาสคือการเขียนไบต์ลงในไฟล์ ไม่มีอะไรซับซ้อน :) FileOutputStream
เป็นหนึ่งในการใช้งานของOutputStream
คลาสนามธรรม ในคอนสตรัคเตอร์ วัตถุของคลาสนี้ใช้พาธไปยังไฟล์เป้าหมาย (ซึ่งควรเขียนไบต์) หรือFile
วัตถุ เราจะตรวจสอบตัวอย่างของแต่ละรายการ:
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
เมื่อสร้างFile
วัตถุ เราส่งเส้นทางที่ต้องการไปยังตัวสร้าง เราไม่จำเป็นต้องสร้างมันล่วงหน้า ถ้าไม่มี โปรแกรมจะสร้างมันขึ้นมา คุณยังสามารถได้รับโดยไม่ต้องสร้างวัตถุเพิ่มเติม เพียงแค่ส่งสตริงที่มีเส้นทาง:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
ผลลัพธ์ในทั้งสองกรณีจะเหมือนกัน เราสามารถเปิดไฟล์ของเราและดูสิ่งต่อไปนี้:
Hi! Welcome to CodeGym — The best site for would-be programmers!
แต่มีความแตกต่างกันเล็กน้อยที่นี่ ลองเรียกใช้โค้ดจากตัวอย่างด้านบนหลายๆ ครั้งติดต่อกัน จากนั้นดูในไฟล์และตอบคำถามนี้: มีกี่บรรทัด แค่หนึ่ง. แต่คุณรันโค้ดหลายครั้ง ปรากฎว่าข้อมูลถูกเขียนทับทุกครั้ง ข้อมูลเก่าจะถูกแทนที่ด้วยข้อมูลใหม่ เราจะทำอย่างไรถ้าไม่เหมาะกับเราและเราต้องเขียนไฟล์ตามลำดับ? ถ้าเราต้องการเขียนคำทักทายลงในไฟล์ 3 ครั้งติดต่อกันล่ะ? ทุกอย่างง่ายมาก เนื่องจากภาษาไม่สามารถรู้ได้ว่าเราต้องการพฤติกรรมใดในแต่ละกรณีFileOutputStream
ผู้เชื่อมโยงสามารถใช้พารามิเตอร์เพิ่มเติมได้ —boolean append
. ถ้าค่าเป็นจริง ข้อมูลจะถูกเขียนต่อท้ายไฟล์ หากเป็นเท็จ (และโดยค่าเริ่มต้นจะเป็นเท็จ) ข้อมูลเก่าจะถูกลบและแทนที่ด้วยข้อมูลใหม่ ตรวจสอบสิ่งนี้โดยรันโค้ดที่แก้ไขของเราสามครั้ง:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
เนื้อหาไฟล์:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
ตอนนี้มันแตกต่างกันแล้ว! อย่าลืมคุณลักษณะนี้เมื่อใช้คลาส I/O มีช่วงหนึ่งที่ฉันใช้เวลาทำงานหลายชั่วโมง ใช้สมองเป็นชั่วโมง พยายามทำความเข้าใจว่าข้อมูลของฉันหายไปจากไฟล์ได้อย่างไร :) และแน่นอน เช่นเดียวกับคลาส I/O อื่นๆ อย่าลืมใช้close()
วิธี เพื่อทรัพยากรฟรี
คลาส FileInputStream
TheFileInputStream
มีจุดประสงค์ตรงกันข้าม — อ่านไบต์จากไฟล์ เช่นเดียวกับFileOutputStream
การสืบทอดOutputStream
คลาสนี้มาจากInputStream
คลาสนามธรรม เราจะเขียนข้อความสองสามบรรทัดในไฟล์ " test.txt " ของเรา:
"So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters"

FileInputStream
:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
int i;
while((i=fileInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
เราอ่านหนึ่งไบต์จากไฟล์ แปลงไบต์ที่อ่านเป็นอักขระและแสดงบนคอนโซล และนี่คือเอาต์พุตคอนโซล:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
คลาส BufferedInputStream
ฉันคิดว่า ด้วยความรู้จากบทเรียนที่ผ่านมา คุณสามารถพูดได้ง่ายๆ ว่าทำไมเราถึงต้องการคลาสนี้BufferedInputStream
และข้อดีอะไรบ้างเมื่อเปรียบเทียบกับFileInputStream
:) เราเคยเจอกับสตรีมแบบบัฟเฟอร์แล้ว ดังนั้นลองเดา (หรือจำ) ก่อนที่คุณจะอ่านต่อ :) สตรีมบัฟเฟอร์จำเป็นเพื่อเพิ่มประสิทธิภาพ I/O เป็นหลัก การเข้าถึงแหล่งข้อมูล เช่น การอ่านจากไฟล์ เป็นการดำเนินการที่มีราคาแพงในแง่ของประสิทธิภาพ และการเข้าถึงไฟล์เพื่ออ่านแต่ละไบต์เป็นการสิ้นเปลือง นั่นเป็นเหตุผลที่BufferedInputStream
ไม่อ่านข้อมูลครั้งละหนึ่งไบต์ แต่อ่านเป็นบล็อก และเก็บไว้ในบัฟเฟอร์พิเศษชั่วคราว สิ่งนี้ช่วยให้เราเพิ่มประสิทธิภาพโปรแกรมโดยลดจำนวนครั้งที่เราเข้าถึงไฟล์ มาดูกันว่าหน้าตาเป็นอย่างไร:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
ที่นี่เราสร้างBufferedInputStream
วัตถุ คอนสตรัคเตอร์ใช้อินสแตนซ์ของInputStream
คลาสหรือลูกหลานของมัน ดังนั้นFileInputStream
จะทำ เป็นอาร์กิวเมนต์เพิ่มเติม จะใช้ขนาดบัฟเฟอร์เป็นไบต์ ด้วยอาร์กิวเมนต์นี้ ข้อมูลจะถูกอ่านจากไฟล์ไม่ใช่ครั้งละหนึ่งไบต์ แต่ครั้งละ 200 ไบต์! ลองนึกดูว่าเราได้ลดจำนวนการเข้าถึงไฟล์ลงมากเพียงใด หากต้องการเปรียบเทียบประสิทธิภาพ คุณสามารถใช้ ไฟล์ข้อความขนาดใหญ่ (ข้อความขนาดหลายเมกะไบต์) และเปรียบเทียบว่าใช้เวลานานเท่าใดในหน่วยมิลลิวินาทีในการอ่านและส่งออกไปยังคอนโซลโดยใช้FileInputStream
และ BufferedInputStream
นี่คือรหัสที่แสดงทั้งสองตัวเลือก:
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");
int i;
while((i = fileInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
เมื่ออ่านไฟล์ขนาด 1.5 MB บนคอมพิวเตอร์ของฉันFileInputStream
ทำงานเสร็จใน ~3500 มิลลิวินาที แต่BufferedInputStream
จัดการได้ใน ~1700 มิลลิวินาที อย่างที่คุณเห็น สตรีมที่บัฟเฟอร์ได้เพิ่มประสิทธิภาพการทำงาน โดยลดไปครึ่งหนึ่ง! :) เราจะเรียนคลาส I/O กันต่อ — แล้วพบกันใหม่!
GO TO FULL VERSION