1. InputStreamReaderlớp học

Một tính năng thú vị khác của các luồng là bạn có thể kết hợp nhiều luồng lại với nhau thành chuỗi . Một luồng có thể đọc dữ liệu không chỉ từ nguồn dữ liệu nội bộ của nó mà còn từ một luồng khác .

Đây là một cơ chế rất mạnh trong Java, cho phép tạo các tình huống đọc dữ liệu phức tạp bằng cách kết nối luồng này với luồng khác. Một kế hoạch như vậy trông như thế này:

Lớp InputStreamReader

Khi một chương trình đọc dữ liệu từ một luồng dữ liệu, luồng dữ liệu sẽ đọc dữ liệu từ nguồn dữ liệu của nó, chẳng hạn như một luồng dữ liệu khác hoặc một tệp.

Hơn nữa, mỗi luồng dữ liệu không chỉ đọc và đưa ra dữ liệu mà còn có thể biến đổi hoặc thực hiện các thao tác khác nhau trên đó. Một ví dụ điển hình về "luồng trung gian" như vậy là lớp InputStreamReaderhọc.

Chúng tôi đã biết một lớp được gọi là FileReader- đó là lớp Readerđọc dữ liệu từ một tệp. Và lấy dữ liệu của nó từ đâu InputStreamReader? Đúng vậy - từ một tệp InputStream.

Khi bạn tạo một InputStreamReaderđối tượng, bạn cần truyền vào một InputStreamđối tượng hoặc một trong các lớp con của nó. Ví dụ:

String src = "c:\\projects\\log.txt";
FileInputStream input = new FileInputStream(src);
InputStreamReader reader = new InputStreamReader(input);

Lớp này InputStreamReadercó tất cả các phương thức mà Readerlớp đó có và chúng hoạt động theo cùng một cách.

Sự khác biệt chính giữa InputStreamReaderlớp và, giả sử, FileReaderlà nơi họ đọc dữ liệu từ đó. FileReaderđọc dữ liệu từ một tệp (duh - đó là lý do tại sao nó được gọi là FileReader), nhưng InputStreamReaderđọc dữ liệu từ tệp InputStream.

Khi bạn đọc một ký tự từ một FileReaderđối tượng bằng read()phương thức này, nó sẽ lần lượt đọc hai byte từ tệp trên đĩa và trả về chúng dưới dạng chars.

Khi bạn đọc một ký tự từ một InputStreamReaderđối tượng bằng read()phương thức này, nó sẽ lần lượt đọc hai byte từ FileInputStreamđối tượng được truyền cho nó, từ đó đọc dữ liệu từ tệp. Kết quả là một chuỗi các cuộc gọi đến read()các phương thức.


2. BufferedReaderlớp học

Một lớp thú vị khác mà bạn có thể sẽ sử dụng nhiều là BufferedReader. Đây cũng là một "luồng trung gian" đọc dữ liệu từ một luồng khác.

Như tên gọi của nó, BufferedReaderlớp này là một lớp con của Readercho phép bạn đọc các ký tự . Nhưng điều thú vị nhất là bạn cũng cần truyền cho nó một nguồn dữ liệu ở dạng luồng mà các ký tự có thể được đọc từ đó , tức là luồng kế thừa Readerlớp.

Vấn đề ở đây là gì? Không giống như InputStreamReader, BufferedReaderlớp không chuyển đổi byte thành ký tự: nó hoàn toàn không chuyển đổi bất kỳ thứ gì. Thay vào đó, nó đệm dữ liệu .

Khi một chương trình đọc một ký tự đơn từ một BufferedReaderđối tượng, đối tượng đó sẽ đọc một mảng lớn các ký tự từ luồng nguồn của nó cùng một lúc. Và lưu trữ chúng trong nội bộ.

Khi ký tự tiếp theo được đọc từ BufferedReaderđối tượng, nó chỉ cần lấy ký tự tiếp theo từ mảng bộ đệm bên trong của nó và trả về ký tự đó mà không cần truy cập nguồn dữ liệu. Chỉ khi tất cả các ký tự trong bộ đệm được sử dụng hết thì nó mới đọc trong một mảng ký tự lớn khác.

Lớp này BufferedReadercũng có một phương thức rất hữu ích — String readLine(), cho phép bạn đọc toàn bộ chuỗi dữ liệu từ luồng nguồn cùng một lúc. Bạn có thể sử dụng phương pháp này để đọc một tệp và hiển thị nội dung của nó trên màn hình theo từng dòng. Ví dụ:

Chúng tôi đã viết cụ thể một số mã nhỏ gọn để minh họa mức độ thuận tiện của điều này. Mã này cũng có thể được viết chi tiết hơn một chút.

String src = "c:\\projects\\log.txt";

try(FileReader in = new FileReader(src);
BufferedReader reader = new BufferedReader(in))
{
   while (reader.ready())
   {
      String line = reader.readLine();
      System.out.println(line);
   }
}
Tạo một FileReaderđối tượng. Nguồn dữ liệu là một tập tin.
Tạo một BufferedReaderđối tượng. Nguồn dữ liệu là một tệp FileReader.
Miễn là vẫn còn dữ liệu trong đầu đọc
Đọc một dòng
Hiển thị dòng
Một điểm quan trọng:

Nếu bạn xâu chuỗi nhiều luồng lại với nhau, thì close()phương thức chỉ cần được gọi trên một trong số chúng. Luồng đó sẽ gọi phương thức trên nguồn dữ liệu của nó, v.v. cho đến khi close()được gọi trên luồng dữ liệu cuối cùng.



3. Đọc từ bảng điều khiển

Và một sự thật thú vị nữa: Scannerlớp không gì khác hơn là một luồng đầu vào trung gian đọc dữ liệu từ System.in, cũng là một luồng dữ liệu.

Đây là hai cách để đọc một dòng từ bảng điều khiển:

lớp máy quét Các lớp BufferedReader và BufferedWriter
InputStream stream = System.in;
Scanner console = new Scanner(stream);
String line = console.nextLine();
InputStream stream = System.in;
InputStreamReader reader = new InputStreamReader(stream);
BufferedReader buff = new BufferedReader(reader);
String line = buff.readLine();

Bạn của chúng ta không gì khác hơn là một biến tĩnh của lớp. Đó là một người có tên là .System.ininSystemInputStreamin

Vì vậy, gần như ngay từ khi bắt đầu học Java trên CodeGym, bạn đã làm việc với các luồng dữ liệu và xây dựng các chuỗi từ chúng. Nhưng bây giờ bạn sẽ làm điều đó một cách có ý thức hơn.