CodeGym /Java блог /Случаен /Четене от клавиатурата: "четци"
John Squirrels
Ниво
San Francisco

Четене от клавиатурата: "четци"

Публикувано в групата
здрасти Уроците и задачите в Ниво 3 ви научиха How да показвате неща на конзолата и, движейки се в другата посока, How да четете данни от клавиатурата.
Четене от клавиатурата: "четци" - 1
Дори се научихте да използвате следната сложна конструкция, за да постигнете това:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Но има един въпрос, на който все още не сме отговорor.

Как, за бога, става това?

В действителност програмите рядко са напълно независими. Те комуникират с други програми, системи, интернет и т.н. Под „комуникация“ имаме предвид основно „обмен на данни“. Тоест те получават няHowви външни данни и също така изпращат някъде вътрешни програмни данни. В ежедневието изобилстват примери за програми за обмен на данни. Например, много уебсайтове ви позволяват да влезете с вашия Facebook or Twitter акаунт, instead of да се регистрирате. В тази ситуация две програми (например Twitter и уебсайтът, в който влизате) обменят необходимите данни. Крайният резултат е, че сте влезли успешно. Думата "поток"се използва за описание на процеса на обмен на данни. Откъде идва това име? Според вашия опит, "поток" може да бъде свързан повече с реки, отколкото с програмиране. Това не е случайно :) Потокът е по същество движеща се част от данни. С други думи, в програмирането не тече вода, а по-скоро данни под формата на byteове и знаци. Можем да получаваме битове данни от поток от данни и след това да ги използваме. Отново ще използваме аналогията вода/поток: можете да загребвате вода от река, за да направите супа, да изгасите огън or да полеете цветята си. Потоците ви позволяват да работите с всеки източник на данни: дали интернет, файловата система на вашия компютър or нещо друго - няма meaning. Потоците са универсален инструмент. Те позволяват на програмата да получава данни отвсякъде (входни потоци) и да ги изпраща навсякъде (изходни потоци). Задачата им е същата: да вземат данни от едно място и да ги изпратят на друго. Има два вида потоци:
  1. Входящите потоци се използват за получаване на данни
  2. Изходните потоци са за изпращане на данни.
В Java тези потоци се реализират от класовете InputStreamи OutputStream. Но потоците могат да бъдат категоризирани по друг начин. В допълнение към входните и изходните потоци, ние също говорим за byteови потоци и символни потоци . Значението тук трябва да е достатъчно ясно: потокът от byteове изпраща информация като набор от byteове, докато потокът от знаци я изпраща като набор от знаци. В този урок ще се спрем на входните потоци. Ще сложа връзка с информация за изходните потоци в края на урока. Можете да го прочетете сами :) Сега погледнете този code:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Когато преминавахте през уроците, не решихте ли, че тази реплика е доста смущаваща? :) Това няма да е така, след като проучим How работи. Нека оправим нещата. Ще започнем от края. System.inе InputStreamобект, екземпляр на класа, за който говорихме по-рано. Това е входен поток, свързан със системно входно устройство (клавиатурата). Между другото, косвено сте запознати с този поток. В крайна сметка вие често използвате неговия „колега“ — System.out! System.outе системният изходен поток. Използва се за извеждане на данни към конзолата чрез любимия ви метод System.out.println(), който използвате постоянно :) System.outе поток за изпращане на данни към конзолата, докатоSystem.inе за получаване на данни от клавиатурата. Всичко е просто :) Нещо повече, можем да четем данни от клавиатурата без тази огромна конструкция. Можем просто да напишем: System.in.read();

public class Main {

   public static void main(String[] args) throws IOException {

       while (true) {
           int x = System.in.read();
           System.out.println(x);
       }
   }
}
Класът InputStream(не забравяйте, че System.inе InputStreamобект) има read()метод, който ви позволява да четете данни. Има един проблем: чете byteове , а не знаци . Скучно е да се използват само английски букви, така че нека се опитаме да прочетем китайския символ "魚" от клавиатурата (просто копирайте тази буква от тук и я поставете в конзолата, като използвате ctrl + v на компютър or Command + v на Mac ) . Този знак между другото означава „риба“. Конзолен изход: 233 173 154 10 Този символ и много други китайски заемат 3 byteа в паметта на компютъра (за разлика от латинските букви, които заемат само 1 byte). В този случай 4 byteа се четат от потока: първите три представляват знака "魚", а другият byte представлява нов ред (Enter). Съответно, System.inв неговия неукрасен вид не е опция за нас. Хората (с редки изключения!) не знаят How да четат byteове. Но InputStreamReaderкласата идва на помощ! Да видим що за животно е това.

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
Преминаваме System.inкъм обекта InputStreamReader . Името на класа го казва! Създаваме InputStreamReaderобект и му предаваме входен поток, от който той ще чете данни. В такъв случай...

new InputStreamReader(System.in)
... ние му казваме, "ще четете данни от системния входен поток (от клавиатурата)". Но това не е единствената му функция! Не InputStreamReaderсамо получава данни от потока. Той също така преобразува потоци от byteове в потоци от знаци . С други думи, вече не е необходимо да преобразувате данните от "единици и нули" на "четим за човека език". InputStreamreaderправи всичко за вас. Разбира се, InputStreamReaderне се ограничава до четене на данни от конзолата. Може да чете данни и от други места. Например от файл:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

   public static void main(String[] args) throws IOException {
       InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("C:\\Users\\username\\Desktop\\testFile.txt"));
   }
}
Тук създаваме FileInputStream(един вариант на InputStream), предаваме пътя на file и предаваме самия поток към InputStreamReader. Сега той ще може да чете данни от file (ако файл действително съществува на пътя, разбира се). Ние също използваме метода InputStreamReaderна класа read()за четене на данни (източникът на данните няма meaning: конзолата, файл or някъде другаде). Каква е разликата между System.in.read()и InputStreamReader.read()?\ Нека отново се опитаме да прочетем знака "魚" с InputStreamReader. Напомням ви Howво всъщност беше прочетено от System.in.read(): 233 173 154 10 И How върши InputStreamReaderсъщата работа?

public class Main {

   public static void main(String[] args) throws IOException {

       InputStreamReader reader = new InputStreamReader(System.in);
       while (true) {
           int x = reader.read();
           System.out.println(x);
       }
   }
}
Конзолен изход: 39770 10 Разликата е очевидна веднага. Последният byte (представляващ новия ред) остава непроменен (числото 10), но знакът "魚" е преобразуван в единичен code "39770". Ето Howво означава да четеш знаци! Ако не вярвате, че 39770 представлява буквата "魚", лесно е да се убедите :)
import java.io.IOException;

public class Main {

   public static void main(String[] args) throws IOException {

       char x = 39770;
       System.out.println(x);
   }
}
Конзолен изход: Но ако InputStreamReaderе толкова страхотен, защо се нуждаем също от BufferedReader? InputStreamReaderзнае How да чете данни и да конвертира byteове в знаци. Какво повече можем да искаме? Защо още един Читател? :/ Отговорът е много прост: за по-голяма производителност и удобство . Да започнем с изпълнението. Когато BufferedReaderчете данни, той използва специална област, наречена буфер, където "съхранява" символите, които чете. В крайна сметка, когато тези знаци са необходими в програмата, те ще бъдат взети от буфера, а не директно от източника на данни (клавиатура, файл и т.н.). Това спестява много ресурси. За да разберете How работи това, представете си куриер в голяма компания. Куриерът седи в офис и чака някой да донесе пакети за доставка. Всеки път, когато получи нов пакет, той може веднага да тръгне на път. Но може да има много пакети през деня. Ще трябва да прави много пътувания между офиса и addressите за доставка. Вместо това куриерът поставя кутия в офиса си. Всеки поставя своите пакети в кутията. Сега куриерът може спокойно да вземе кутията и да се движи от address на address. Това спестява много време, защото не се налага всеки път да се връща в офиса. В този пример кутията е просто буфер, а офисът е източник на данни. За куриера е много по-лесно да вземе пакети от една кутия, когато прави доставки, отколкото да се връща в офиса всеки път. Ще спести и бензин. По същия начин, в една програма е много по-малко ресурсоемко да се вземат данни от буфер, отколкото да се препраща към източника на данни всеки път. Като резултат,BufferedReader+ InputStreamReaderе по-бърз, отколкото InputStreamReaderсам . Обмислихме представянето. Какво ще кажете за удобството? Основното предимство е, че Bufferedreaderможе да чете данни не само един знак наведнъж (въпреки че може да прави това със своя read()метод), но и цели редове наведнъж! Това става с помощта на readLine()метода;

public class Main {

   public static void main(String[] args) throws IOException {

       BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
       String s = reader.readLine();
       System.out.println("We read this line from the keyboard:");
       System.out.println(s);
   }
}
Конзолен изход: CodeGym е най-добрият уебсайт за изучаване на Java! Четем този ред от клавиатурата: CodeGym е най-добрият уебсайт за изучаване на Java! Това е особено полезно при четене на големи количества данни. Четенето на един or два реда текст символ по знак все още е възможно. Но четенето във "Война и мир" буква по буква би било малко проблематично :)
Коментари
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION