CodeGym /Blog Java /Ngẫu nhiên /Đầu vào/đầu ra trong Java. Các lớp FileInputStream, FileO...

Đầu vào/đầu ra trong Java. Các lớp FileInputStream, FileOutputStream và BufferedInputStream

Xuất bản trong nhóm
"Xin chào! Trong bài học hôm nay, chúng ta sẽ tiếp tục cuộc trò chuyện về luồng đầu vào và đầu ra trong Java ( Java I/O ). Đây không phải là bài học đầu tiên về chủ đề này và chắc chắn sẽ không phải là bài học cuối cùng :) Đầu vào/đầu ra trong Java.  Các lớp FileInputStream, FileOutputStream và BufferedInputStream - 1Vì nó xảy ra, ngôn ngữ Java cung cấp nhiều cách để làm việc với I/O. Có khá nhiều lớp thực hiện chức năng này, vì vậy chúng tôi đã chia chúng thành nhiều bài học — để bạn không bị nhầm lẫn ngay từ đầu :) Trước đây bài học, chúng ta đã đề cập đến BufferedReader, cũng như InputStreamcác OutputStreamlớp trừu tượng và một số lớp con. Hôm nay chúng ta sẽ xem xét 3 lớp mới: FileInputStream,  FileOutputStream, và  BufferedInputStream.

Lớp FileOutputStream

Mục đích chính của FileOutputStreamlớp là ghi byte vào một tệp. Không có gì phức tạp :) FileOutputStreamlà một trong những triển khai của OutputStreamlớp trừu tượng. Trong hàm tạo, các đối tượng của lớp này lấy đường dẫn đến tệp đích (nơi các byte sẽ được ghi) hoặc một Fileđối tượng. Chúng tôi sẽ kiểm tra các ví dụ về từng:

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(); 
   } 
}
Khi tạo Fileđối tượng, chúng tôi đã chuyển đường dẫn mong muốn tới hàm tạo. Chúng ta không cần phải tạo nó trước: nếu nó không tồn tại, chương trình sẽ tạo ra nó. Bạn cũng có thể thực hiện mà không cần tạo đối tượng bổ sung, chỉ cần chuyển một chuỗi có đường dẫn:

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(); 
   } 
} 
Kết quả trong cả hai trường hợp sẽ giống nhau. Chúng tôi có thể mở tệp của mình và xem những điều sau đây:

Hi! Welcome to CodeGym — The best site for would-be programmers!
Nhưng có một sắc thái ở đây. Hãy thử chạy mã từ ví dụ trên nhiều lần liên tiếp. Sau đó xem trong tệp và trả lời câu hỏi này: tệp có bao nhiêu dòng? Chỉ một. Nhưng bạn đã chạy mã nhiều lần. Hóa ra là dữ liệu luôn bị ghi đè — dữ liệu cũ được thay thế bằng dữ liệu mới. Chúng tôi phải làm gì nếu điều đó không phù hợp với chúng tôi và chúng tôi cần ghi tuần tự vào tệp? Điều gì sẽ xảy ra nếu chúng ta muốn viết lời chào của mình vào một tệp ba lần liên tiếp? Tất cả đều rất đơn giản. Vì ngôn ngữ không thể biết chúng ta cần hành vi nào trong từng trường hợp, nên bộ FileOutputStreamđiều khiển có thể lấy một tham số bổ sung —boolean append. Nếu giá trị của nó là true, dữ liệu sẽ được ghi vào cuối tệp. Nếu nó sai (và theo mặc định là sai), mọi dữ liệu cũ sẽ bị xóa và thay thế bằng dữ liệu mới. Hãy kiểm tra điều này bằng cách chạy mã đã sửa đổi của chúng tôi ba lần:

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(); 
   } 
} 
Nội dung tệp:

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!
Bây giờ thì khác! Đừng quên tính năng này khi sử dụng các lớp I/O. Đã có lúc tôi dành hàng giờ cho các nhiệm vụ, vắt óc hàng giờ, cố gắng hiểu làm thế nào mà dữ liệu của tôi biến mất khỏi tệp :) Và tất nhiên, cũng giống như các lớp I/O khác, đừng quên sử dụng phương close()thức để giải phóng tài nguyên.

Lớp FileInputStream

Mục FileInputStreamđích ngược lại - đọc byte từ một tệp. Cũng giống như FileOutputStreaminherits OutputStream, lớp này kế thừa từ InputStreamlớp trừu tượng. Chúng tôi sẽ viết một vài dòng văn bản trong tệp " test.txt " của chúng tôi:

"So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters"
Đầu vào/đầu ra trong Java.  Các lớp FileInputStream, FileOutputStream và BufferedInputStream - 2Đây là cách đọc dữ liệu từ một tệp bằng cách sử dụng 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); 

       } 
   } 
}
Chúng tôi đọc một byte từ tệp, chuyển đổi các byte đã đọc thành các ký tự và hiển thị chúng trên bàn điều khiển. Và đây là đầu ra của giao diện điều khiển:

So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters

Lớp BufferedInputStream

Tôi nghĩ, với kiến ​​thức từ các bài học trước, bạn có thể dễ dàng nói tại sao chúng ta cần lớp này BufferedInputStreamvà nó có những ưu điểm gì so với FileInputStream:) Chúng ta đã gặp phải các luồng được đệm, vì vậy hãy thử đoán (hoặc ghi nhớ) trước khi bạn tiếp tục đọc :) Luồng đệm chủ yếu cần thiết để tối ưu hóa I/O. Truy cập một nguồn dữ liệu, chẳng hạn như đọc từ một tệp, là một hoạt động tốn kém về mặt hiệu suất Và để truy cập một tệp để đọc từng byte là lãng phí. Đó là lý do tại sao BufferedInputStreamđọc dữ liệu không phải từng byte một mà theo từng khối và lưu trữ tạm thời chúng trong một bộ đệm đặc biệt. Điều này cho phép chúng tôi tối ưu hóa chương trình bằng cách giảm số lần chúng tôi truy cập tệp. Hãy xem nó trông như thế nào:

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); 
       } 
   } 
} 
Ở đây chúng tôi đã tạo một BufferedInputStreamđối tượng. Phương thức khởi tạo của nó lấy một thể hiện của InputStreamlớp hoặc bất kỳ lớp con nào của lớp đó FileInputStream. Là một đối số bổ sung, nó lấy kích thước bộ đệm tính bằng byte. Nhờ đối số này, giờ đây dữ liệu sẽ được đọc từ tệp không phải một byte mỗi lần mà là 200 byte mỗi lần! Hãy tưởng tượng chúng tôi đã giảm số lần truy cập tệp đến mức nào. Để so sánh hiệu suất, bạn có thể lấy một tệp văn bản lớn (vài megabyte văn bản) và so sánh thời gian mất bao lâu để đọc và xuất ra bảng điều khiển bằng cách sử dụng FileInputStreamBufferedInputStream. Đây là mã thể hiện cả hai tùy chọn:

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())); 
   }
}
Khi đọc tệp 1,5 MB trên máy tính của tôi, FileInputStreamtôi đã hoàn thành công việc trong ~3500 mili giây, nhưng BufferedInputStreamquản lý nó trong ~1700 mili giây. Như bạn có thể thấy, luồng đệm đã tối ưu hóa công việc, cắt giảm một nửa! :) Chúng ta sẽ tiếp tục học các lớp I/O — hẹn gặp lại!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION