สวัสดี! บทเรียนและงานในระดับ 3 จะสอนวิธีแสดงข้อมูลบนคอนโซล และวิธีอ่านข้อมูลจากแป้นพิมพ์ในอีกทิศทางหนึ่ง
การอ่านจากแป้นพิมพ์: "ผู้อ่าน" - 1
คุณยังได้เรียนรู้การใช้โครงสร้างที่ซับซ้อนต่อไปนี้เพื่อทำสิ่งนี้ให้สำเร็จ:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
แต่มีคำถามหนึ่งที่เรายังไม่ได้ตอบ

มันทำงานอย่างไรในโลกนี้?

ในความเป็นจริง โปรแกรมต่างๆ แทบไม่มีความเป็นอิสระจากกันโดยสิ้นเชิง พวกเขาสื่อสารกับโปรแกรม ระบบ อินเทอร์เน็ต ฯลฯ โดย "สื่อสาร" เราหมายถึง "แลกเปลี่ยนข้อมูล" เป็นหลัก นั่นคือพวกเขาได้รับข้อมูลภายนอกและส่งข้อมูลโปรแกรมภายในไปที่ไหนสักแห่ง ตัวอย่างโปรแกรมแลกเปลี่ยนข้อมูลที่มีอยู่มากมายในชีวิตประจำวัน ตัวอย่างเช่น เว็บไซต์จำนวนมากให้คุณลงชื่อเข้าใช้ด้วยบัญชี Facebook หรือ Twitter แทนการลงทะเบียน ในสถานการณ์นี้ โปรแกรมสองโปรแกรม (เช่น Twitter และเว็บไซต์ที่คุณลงชื่อเข้าใช้) จะแลกเปลี่ยนข้อมูลที่จำเป็น ผลสุดท้ายคือคุณลงชื่อเข้าใช้สำเร็จ คำว่า"สตรีม"ใช้เพื่ออธิบายกระบวนการแลกเปลี่ยนข้อมูล ชื่อนี้มาจากไหน? จากประสบการณ์ของคุณ "ลำธาร" อาจเกี่ยวข้องกับแม่น้ำมากกว่าการเขียนโปรแกรม นั่นไม่ใช่เรื่องบังเอิญ :) โดยพื้นฐานแล้วสตรีมคือชิ้นส่วนของข้อมูลที่เคลื่อนไหว กล่าวอีกนัยหนึ่ง ในการเขียนโปรแกรม ไม่ใช่น้ำที่ไหล แต่เป็นข้อมูลในรูปของไบต์และอักขระ เราสามารถรับบิตข้อมูลจากสตรีมข้อมูลแล้วนำไปใช้ได้ อีกครั้ง เราจะใช้การเปรียบเทียบน้ำ/การไหล: คุณสามารถตักน้ำจากแม่น้ำเพื่อทำซุป ดับไฟ หรือรดน้ำดอกไม้ของคุณ สตรีมช่วยให้คุณทำงานกับแหล่งข้อมูลใดก็ได้ ไม่ว่าจะเป็นอินเทอร์เน็ต ระบบไฟล์ของคอมพิวเตอร์ของคุณ หรืออย่างอื่น ก็ไม่สร้างความแตกต่าง สตรีมเป็นเครื่องมือสากล พวกเขาอนุญาตให้โปรแกรมรับข้อมูลจากทุกที่ (สตรีมอินพุต) และส่งได้ทุกที่ (สตรีมเอาต์พุต) งานของพวกเขาเหมือนกัน: รับข้อมูลจากที่หนึ่งและส่งไปยังอีกที่หนึ่ง สตรีมมีสองประเภท:
  1. สตรีม อินพุตใช้เพื่อรับข้อมูล
  2. เอาต์พุต สตรีมสำหรับการส่งข้อมูล
ใน Java สตรีมเหล่านี้ถูกนำไปใช้โดยInputStreamand OutputStreamคลาส แต่สตรีมสามารถจัดประเภทได้อีกทางหนึ่ง นอกจากสตรีมอินพุตและเอาท์พุตแล้ว เรายังพูดถึงไบต์สตรีมและสตรีมอักขระ ด้วย ความหมายในที่นี้ควรชัดเจนเพียงพอ: ไบต์สตรีมจะส่งข้อมูลเป็นชุดของไบต์ ในขณะที่สตรีมอักขระจะส่งเป็นชุดอักขระ ในบทเรียนนี้ เราจะพูดถึงอินพุตสตรีม ฉันจะใส่ลิงก์ที่มีข้อมูลเกี่ยวกับเอาต์พุตสตรีมไว้ที่ท้ายบทเรียน คุณสามารถอ่านได้ด้วยตัวคุณเอง :) ตอนนี้ดูที่รหัสนี้:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
เมื่อผ่านบทเรียน คุณไม่คิดว่าบรรทัดนี้ค่อนข้างน่ากลัวหรือไม่? :) นั่นจะไม่เป็นเช่นนั้นเมื่อเราได้สำรวจวิธีการทำงานแล้ว มาทำสิ่งที่ถูกต้องกันเถอะ เราจะเริ่มต้นในตอนท้าย 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()เมธอดที่ให้คุณอ่านข้อมูลได้ มีปัญหาอย่างหนึ่ง: มันอ่านbytesไม่ใช่character การใช้ตัวอักษรภาษาอังกฤษเพียงอย่างเดียวเป็นเรื่องน่าเบื่อ ดังนั้นลองอ่านตัวอักษรจีน "魚" จากแป้นพิมพ์ (เพียงคัดลอกตัวอักษรนี้จากที่นี่และวางลงในคอนโซลโดยใช้ ctrl + vบนพีซีหรือCommand + vบน Mac) อักขระนี้หมายถึง 'ปลา' โดยวิธีการ เอาต์พุตคอนโซล: 233 173 154 10 สัญลักษณ์นี้และภาษาจีนอื่นๆ จำนวนมากใช้ 3 ไบต์ในหน่วยความจำของคอมพิวเตอร์ (ต่างจากตัวอักษรละตินที่ใช้เพียง 1 ไบต์) ในกรณีนี้ 4 ไบต์ถูกอ่านจากสตรีม: สามไบต์แรกแทนอักขระ "魚" และไบต์อื่นๆ แทนบรรทัดใหม่ (Enter) ดังนั้นSystem.inในรูปแบบที่ปราศจากการตกแต่งจึงไม่ใช่ตัวเลือกสำหรับเรา มนุษย์ (มีข้อยกเว้นที่หายาก!) ไม่รู้วิธีอ่านไบต์ แต่ InputStreamReaderชั้นมาช่วยทัน! มาดูกันว่านี่คือสัตว์ชนิดใด

BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
เราส่งผ่านSystem.inไปยังวัตถุInputStreamReader ชื่อชั้นบอกเลย! เราสร้างInputStreamReaderออบเจกต์และส่งผ่านอินพุตสตรีมที่มันจะอ่านข้อมูล ในกรณีนี้...

new InputStreamReader(System.in)
...เราบอกมันว่า "คุณจะอ่านข้อมูลจากสตรีมอินพุตของระบบ (จากแป้นพิมพ์)" แต่นี่ไม่ใช่หน้าที่เดียว! ไม่InputStreamReaderได้รับข้อมูลจากสตรีมเท่านั้น นอกจากนี้ยังแปลงไบต์สตรีมเป็นสตรีมอักขระ กล่าวอีกนัยหนึ่ง คุณไม่จำเป็นต้องแปลงข้อมูลจาก "หนึ่งและศูนย์" เป็น "ภาษาที่มนุษย์อ่านได้" อีกต่อไป 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) ส่งผ่านเส้นทางของไฟล์ และส่งสตรีมไปยังไฟล์InputStreamReader. ตอนนี้จะสามารถอ่านข้อมูลจากไฟล์ได้ (หากไฟล์มีอยู่จริงที่เส้นทาง) เรายังใช้ วิธีการ InputStreamReaderของคลาสread()เพื่ออ่านข้อมูล (แหล่งที่มาของข้อมูลไม่สำคัญ: คอนโซล ไฟล์ หรือที่อื่น) System.in.read()และ ?\ ต่างกันอย่างไรInputStreamReader.read()มาลองอ่านอักขระ "魚" อีกครั้งด้วยInputStreamReaderเครื่องหมาย ฉันเตือนคุณถึงสิ่งที่อ่านโดยSystem.in.read(): 233 173 154 10 แล้วสิ่ง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 ความแตกต่างนั้นชัดเจนในทันที ไบต์สุดท้าย (แทนบรรทัดใหม่) ยังคงไม่เปลี่ยนแปลง (หมายเลข 10) แต่อักขระ "魚" ถูกแปลงเป็นรหัสเดียว "39770" นี่คือความหมายของการอ่านอักขระ! หากคุณไม่เชื่อว่า 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รู้วิธีอ่านข้อมูลและแปลงไบต์เป็นอักขระ เราจะขออะไรอีก ทำไมผู้อ่านคนอื่น? :/ คำตอบนั้นง่ายมาก: เพื่อประสิทธิภาพและ ความ สะดวกสบาย ที่มากขึ้น เริ่มจากประสิทธิภาพกันก่อน เมื่อBufferedReaderอ่านข้อมูล จะใช้พื้นที่พิเศษที่เรียกว่าบัฟเฟอร์ ซึ่งจะ "เก็บ" อักขระที่อ่าน ท้ายที่สุด เมื่ออักขระเหล่านี้จำเป็นต้องใช้ในโปรแกรม อักขระเหล่านี้จะถูกดึงมาจากบัฟเฟอร์ ไม่ใช่จากแหล่งข้อมูลโดยตรง (แป้นพิมพ์ ไฟล์ ฯลฯ) ช่วยประหยัดทรัพยากรได้มาก เพื่อให้เข้าใจถึงวิธีการทำงาน ลองนึกภาพพนักงานส่งของในบริษัทขนาดใหญ่ คนส่งของนั่งอยู่ในสำนักงานเพื่อรอใครสักคนนำพัสดุมาส่ง ทุกครั้งที่เขาได้รับแพ็คเกจใหม่ เขาสามารถออกเดินทางได้ทันที แต่อาจมีแพ็คเกจจำนวนมากในระหว่างวัน เขาจะต้องเดินทางหลายครั้งระหว่างสำนักงานและที่อยู่จัดส่ง คนส่งของจะวางกล่องไว้ในที่ทำงานของเขาแทน ทุกคนใส่ของลงในกล่อง ตอนนี้ผู้จัดส่งสามารถรับกล่องและย้ายจากที่อยู่หนึ่งไปยังอีกที่อยู่หนึ่งได้อย่างใจเย็น สิ่งนี้ช่วยประหยัดเวลาได้มากเพราะเขาไม่ต้องกลับไปที่สำนักงานทุกครั้ง ในตัวอย่างนี้ กล่องเป็นเพียงบัฟเฟอร์ และสำนักงานเป็นแหล่งข้อมูล พนักงานส่งของรับพัสดุจากกล่องเดียวเมื่อทำการจัดส่งได้ง่ายกว่าการกลับไปที่สำนักงานทุกครั้ง เขาจะประหยัดน้ำมันด้วย ในทำนองเดียวกัน ในโปรแกรม การนำข้อมูลจากบัฟเฟอร์มาใช้ทรัพยากรน้อยกว่าการอ้างถึงแหล่งข้อมูลในแต่ละครั้ง ผลที่ตามมา,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! สิ่งนี้มีประโยชน์อย่างยิ่งเมื่ออ่านข้อมูลจำนวนมาก การอ่านข้อความทีละหนึ่งหรือสองบรรทัดยังคงเป็นไปได้ แต่การอ่านใน "สงครามและสันติภาพ" ทีละตัวอักษรอาจเป็นปัญหาเล็กน้อย :)