JavaRush /Blog Java /Random-VI /Vào/ra trong Java. Các lớp FileInputStream, FileOutputStr...

Vào/ra trong Java. Các lớp FileInputStream, FileOutputStream, BufferedInputStream

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

Lớp FileOutputStream

Mục đích chính của lớp FileOutputStream là ghi byte vào một tệp. Không có gì phức tạp :) FileOutputStream là một trong những triển khai của lớp OutputStream 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 (mà các byte cần được ghi vào đó) hoặc một đối tượng của lớp File. Hãy xem xét cả hai ví dụ:
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();
   }
}
Khi tạo một đối tượng, Filechúng ta đã chỉ định trong hàm tạo đường dẫn nơi nó sẽ được đặt. Không cần phải tạo trước: nếu nó không tồn tại, chương trình sẽ tự tạo. Bạn có thể thực hiện mà không cần tạo thêm đối tượng và chỉ cần truyền một chuỗi có địa chỉ:
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();
   }
}
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 ở đó:

Hello! Добро пожаловать на JavaRush — лучший сайт для тех, кто хочет стать программистом!
Tuy nhiên, có một lưu ý ở đây. Hãy thử chạy mã từ ví dụ trên vài lần liên tiếp, sau đó xem tệp và trả lời câu hỏi: bạn thấy có bao nhiêu dòng được viết trong đó? Chỉ một. Nhưng bạn đã chạy mã nhiều lần. Tuy nhiên, hóa ra dữ liệu lần nào cũng bị ghi đè, thay thế dữ liệu cũ. Điều gì sẽ xảy ra nếu chúng tôi không hài lòng với điều này và cần ghi âm tuần tự? Điều gì sẽ xảy ra nếu chúng ta muốn viết lời chào vào một tập tin ba lần liên tiếp? Mọi thứ đều đơn giản ở đây. Vì bản thân ngôn ngữ không thể biết chúng ta cần loại hành vi nào trong từng trường hợp nên FileOutputStreambạn có thể chuyển một tham số bổ sung cho hàm tạo - boolean append. Nếu giá trị của nó là true thì dữ liệu sẽ được ghi vào cuối file. Nếu sai (và giá trị mặc định là sai ), dữ liệu cũ sẽ bị xóa và dữ liệu mới sẽ được ghi. Hãy kiểm tra và 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 JavaRush - the best site for those who want to become a programmer!\r\n";

       fileOutputStream.write(greetings.getBytes());

       fileOutputStream.close();
   }
}
Kết quả trong tập tin:

Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Cái khác! Hãy ghi nhớ tính năng này khi sử dụng các lớp I/O. Có lúc, tôi phải ngồi làm nhiệm vụ hàng giờ để hiểu dữ liệu cũ của mình đã đi đâu từ các tệp :) Và tất nhiên, như trong trường hợp của các lớp I/O khác, đừng quên giải phóng tài nguyên thông qua close().

Lớp FileInputStream

Lớp này có FileInputStreammục đích ngược lại - đọc byte từ một tệp. Cũng giống như FileOutputStreamlớp kế thừa OutputStream, lớp này bắt nguồn từ lớp trừu tượng InputStream. Hãy viết một vài dòng văn bản vào văn bản “ 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»
Vào/ra trong Java.  Các lớp FileInputStream, FileOutputStream, BufferedInputStream - 2 Đây là cách thực hiện đọ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 ký tự và xuất chúng ra bảng điều khiển. Và đây là kết quả trong bảng đ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 giảng trước, bạn có thể dễ dàng biết tại sao lớp học này lại cần thiết BufferedInputStreamvà nó có những ưu điểm gì FileInputStream:) Chúng ta đã gặp các luồng đệm, vì vậy hãy thử đoán (hoặc ghi nhớ) trước khi tiếp tục đọc :) Luồng đệm cần thiết chủ yếu để tối ưu hóa I/O. Truy cập nguồn dữ liệu, chẳng hạn như đọc từ tệp, là một hoạt động đòi hỏi nhiều hiệu năng. Và việc truy cập tệp để đọc một byte mỗi lần là lãng phí. Do đó, BufferedInputStreamnó đọc dữ liệu không phải một byte mỗi lần mà theo 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 hoạt động của chương trình bằng cách giảm số lượng truy cập vào 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 ra một đối tượng BufferedInputStream. Nó chấp nhận một đối tượng hoặc bất kỳ đối tượng kế thừa nào của nó làm đầu vào InputStream, vì vậy đối tượng trước đó FileInputStreamsẽ làm như vậy. Nó lấy kích thước bộ đệm tính bằng byte làm tham số bổ sung. Giờ đây, nhờ điều nà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 ta đã giảm số lượng 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 số tệp văn bản lớn có kích thước vài megabyte và so sánh thời gian cần thiết để đọc và xuất nó ra bảng điều khiển tính bằng mili giây bằng cách sử dụng FileInputStreamBufferedInputStream. Dưới đây là cả hai ví dụ về mã:
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, FileInputStreamnó thực hiện công việc trong ~3500 mili giây, nhưng ở đây BufferedInputStreamnó thực hiện công việc trong ~1700 mili giây. Như bạn có thể thấy, luồng được đệm đã tối ưu hóa hiệu suất của chương trình lên gấp 2 lần! :) 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