1. InputStreamReaderклас

Друга интересна характеристика на потоците е, че можете да комбинирате множество потоци заедно във вериги . Потокът може да чете данни не само от своя вътрешен източник на данни, но и от друг поток .

Това е много мощен механизъм в Java, който прави възможно създаването на сложни сценарии за четене на данни чрез свързване на един поток към друг. Такава схема изглежда така:

Клас InputStreamReader

Когато една програма чете данни от поток от данни, потокът от данни на свой ред чете данните от своя източник на данни, който е друг поток от данни or файл, например.

Нещо повече, всеки поток от данни не само чете и издава данни, но също така може да ги трансформира or да извършва различни операции върху тях. Добър пример за такъв "междинен поток" е класът InputStreamReader.

Вече знаем клас, наречен FileReader— това е Reader, който чете данни от файл. И откъде InputStreamReaderима данните? Точно така — от InputStream.

Когато създавате InputStreamReaderобект, трябва да предадете InputStreamобект or един от неговите наследствени класове. Пример:

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

Класът InputStreamReaderима всички методи, които Readerкласът има, и те работят по абсолютно същия начин.

Основната разлика между InputStreamReaderкласа и, да речем, FileReaderе откъде четат данни. FileReaderчете данни от файл (да — затова се нарича FileReader), но InputStreamReaderчете данни от InputStream.

Когато четете знак от FileReaderобект с помощта на read()метода, той от своя страна чете два byteа от file на диска и ги връща като chars.

Когато четете символ от InputStreamReaderобект с помощта на read()метода, той от своя страна чете два byteа от FileInputStreamобекта, който му е предаден, което от своя страна чете данни от file. Резултатът е верига от извиквания на read()методи.


2. BufferedReaderклас

Друг интересен клас, който вероятно ще използвате често, е BufferedReader. Това също е "междинен поток", който чете данни от друг поток.

Както подсказва името му, BufferedReaderкласът е подклас на Readerи ви позволява да четете знаци . Но най-интересното е, че вие ​​също трябва да му предадете източник на данни под формата на поток, от който могат да се четат символи , т.е. поток, който наследява Readerкласа.

Какъв е смисълът? За разлика от InputStreamReader, BufferedReaderкласът не преобразува byteове в знаци: той изобщо не преобразува нищо. Вместо това буферира данните .

Когато една програма чете един знак от BufferedReaderобект, обектът чете наведнъж голям набор от знаци от своя изходен поток. И ги съхранява вътрешно.

Когато следващият знак бъде прочетен от BufferedReaderобекта, той просто грабва следващия знак от своя вътрешен буферен масив и го връща без достъп до източника на данни. Само когато всички символи в буфера са изразходвани, той чете друг голям масив от знаци.

Класът BufferedReaderсъщо има много полезен метод — String readLine(), който ви позволява да четете цели низове от данни от изходния поток наведнъж. Можете да използвате този метод, да речем, да прочетете файл и да покажете съдържанието му на екрана ред по ред. Пример:

Специално написахме компактен code, за да илюстрираме колко удобно може да бъде това. Този code също може да бъде написан с малко повече подробности.

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);
   }
}
Създайте FileReaderобект. Източникът на данни е файл.
Създайте BufferedReaderобект. Източникът на данни е FileReader.
Докато все още има данни в четеца
Прочетете един ред
Покажете реда
Важен момент:

Ако свържете заедно няколко потока, тогава close()методът трябва да бъде извикан само на един от тях. Този поток ще извика метода на неговия източник на данни и така нататък, докато не close()бъде извикан на последния поток от данни.



3. Четене от конзолата

И още един интересен факт: Scannerкласът не е нищо повече от междинен входен поток, който чете данни от System.in, който също е поток от данни.

Ето два начина за четене на ред от конзолата:

Клас скенер Класове BufferedReader и 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();

Нашият приятел не е нищо повече от статична променлива на класа. Това е човек , чието име е .System.ininSystemInputStreamin

Така че почти от самото начало на вашето обучение по Java в CodeGym, вие работите с потоци от данни и изграждате вериги от тях. Но сега ще го направите по-съзнателно.