สวัสดี! ในการบรรยายวันนี้ เราจะพูดคุยกันต่อเกี่ยวกับสตรีมอินพุตและเอาท์พุตใน Java หรือ เรียกสั้น ๆ ว่า Java I/O (“อินพุต-เอาต์พุต”) นี่ไม่ใช่การบรรยายครั้งแรกในหัวข้อนี้ และจะไม่ใช่ครั้งสุดท้าย :) มันบังเอิญว่า Java ในฐานะภาษาหนึ่งให้โอกาสมากมายในการทำงานกับอินพุต/เอาท์พุต มีคลาสค่อนข้างมากที่ใช้ฟังก์ชันนี้ ดังนั้นเราจึงแบ่งคลาสออกเป็นหลายคลาสเพื่อที่คุณจะได้ไม่สับสนในตอนแรก :) ในการบรรยายครั้งก่อนๆ เราได้พูดถึงBufferedReaderเช่นเดียวกับคลาสนามธรรมInputStream & OutputStreamและอีกหลายคลาส ลูกหลาน วันนี้เราจะดูคลาสใหม่ 3 คลาส: FileInputStream , FileOutputStreamและBufferedInputStream
คลาส FileOutputStream
วัตถุประสงค์หลักของ คลาส FileOutputStreamคือการเขียนไบต์ไปยังไฟล์ ไม่มีอะไรซับซ้อน :) FileOutputStreamเป็นหนึ่งในการใช้งานของคลาสOutputStreamนามธรรม ใน Constructor อ็อบเจ็กต์ของคลาสนี้จะใช้พาธไปยังไฟล์เป้าหมาย (ซึ่งจำเป็นต้องเขียนไบต์) หรืออ็อบเจ็กต์ของ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 JavaRush - the best site for those who want to become a programmer!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
เมื่อสร้างวัตถุFile
เราได้ระบุไว้ใน Constructor ว่าควรอยู่ที่ใด ไม่จำเป็นต้องสร้างไว้ล่วงหน้า หากไม่มี โปรแกรมจะสร้างเอง คุณสามารถทำได้โดยไม่ต้องสร้างวัตถุเพิ่มเติมและเพียงแค่ส่งสตริงที่มีที่อยู่:
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 JavaRush - the best site for those who want to become a programmer!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
ผลลัพธ์ในทั้งสองกรณีจะเหมือนกัน เราสามารถเปิดไฟล์ของเราและดูที่นั่น:
Hello! Добро пожаловать на JavaRush — лучший сайт для тех, кто хочет стать программистом!
อย่างไรก็ตามมีข้อแม้ประการหนึ่งที่นี่ ลองรันโค้ดจากตัวอย่างด้านบนหลายๆ ครั้งติดต่อกัน จากนั้นดูไฟล์และตอบคำถาม: คุณเห็นข้อความเขียนอยู่ในนั้นกี่บรรทัด? แค่หนึ่ง. แต่คุณรันโค้ดหลายครั้ง อย่างไรก็ตามปรากฎว่าข้อมูลถูกเขียนทับในแต่ละครั้งโดยแทนที่ข้อมูลเก่า จะเป็นอย่างไรถ้าเราไม่พอใจกับสิ่งนี้และต้องการการบันทึกตามลำดับ? จะเป็นอย่างไรหากเราต้องการเขียนคำทักทายของเราลงในไฟล์สามครั้งติดต่อกัน? ทุกอย่างเรียบง่ายที่นี่ เนื่องจากตัวภาษาเองไม่สามารถรู้ได้ว่าเราต้องการพฤติกรรมประเภทใดในแต่ละกรณีFileOutputStream
คุณจึงสามารถส่งพารามิเตอร์เพิ่มเติมไปยังตัวสร้างได้boolean append
- หากค่าเป็นtrueข้อมูลจะถูกเขียนที่ส่วนท้ายของไฟล์ หากเป็นเท็จ (และค่าเริ่มต้นคือfalse ) ข้อมูลเก่าจะถูกลบและข้อมูลใหม่จะถูกเขียน มาทดสอบและรันโค้ดที่แก้ไขของเราสามครั้ง:
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 JavaRush - the best site for those who want to become a programmer!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
ผลลัพธ์ในไฟล์:
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
อีกสิ่งหนึ่งที่! คำนึงถึงคุณลักษณะนี้เมื่อใช้คลาส I/O ครั้งหนึ่ง ฉันต้องนั่งทำงานเป็นเวลาหลายชั่วโมงเพื่อทำความเข้าใจว่าข้อมูลเก่าของฉันไปจากไฟล์ไหน :) และแน่นอนว่า เช่นเดียวกับในกรณีของคลาส I/O อื่นๆ อย่าลืมเกี่ยวกับการปล่อยทรัพยากรผ่านclose()
.
คลาส FileInputStream
คลาสมีFileInputStream
วัตถุประสงค์ตรงกันข้าม - การอ่านไบต์จากไฟล์ เช่นเดียวกับการ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
ที่นี่เราได้ สร้าง วัตถุ มันยอมรับวัตถุหรือตัวต่อๆ ไปเป็น input 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 มิลลิวินาที อย่างที่คุณเห็น สตรีมบัฟเฟอร์ได้เพิ่มประสิทธิภาพการทำงานของโปรแกรมเป็น 2 เท่า! :) เราจะศึกษาคลาส I/O ต่อไป - แล้วพบกันใหม่!
GO TO FULL VERSION