กระแสคืออะไร?


145

กระแสในโลกแห่งการเขียนโปรแกรมคืออะไร? ทำไมเราถึงต้องการ?

กรุณาอธิบายด้วยความช่วยเหลือของการเปรียบเทียบถ้าเป็นไปได้


10
นี้เป็นซ้ำstackoverflow.com/questions/507747/...
John Saunders

คำตอบ:


171

สตรีมแสดงลำดับของออบเจ็กต์ (โดยปกติคือไบต์ แต่ไม่จำเป็นต้องเป็นเช่นนั้น) ซึ่งสามารถเข้าถึงได้ตามลำดับ การดำเนินการทั่วไปในสตรีม:

  • อ่านหนึ่งไบต์ ครั้งต่อไปที่คุณอ่านคุณจะได้รับไบต์ถัดไปและอื่น ๆ
  • อ่านหลายไบต์จากสตรีมไปยังอาร์เรย์
  • ค้นหา (ย้ายตำแหน่งปัจจุบันของคุณในสตรีมดังนั้นในครั้งต่อไปที่คุณอ่านคุณจะได้รับไบต์จากตำแหน่งใหม่)
  • เขียนหนึ่งไบต์
  • เขียนหลายไบต์จากอาร์เรย์ลงในสตรีม
  • ข้ามไบต์จากสตรีม (เหมือนกับอ่าน แต่คุณไม่สนใจข้อมูลหรือถ้าคุณต้องการก็เหมือนค้นหา แต่สามารถส่งต่อได้เท่านั้น)
  • ดันไบต์กลับเข้าไปในอินพุตสตรีม (ซึ่งเหมือนกับการ "เลิกทำ" สำหรับการอ่าน - คุณต้องสำรองข้อมูลสตรีมไว้สองสามไบต์เพื่อที่ครั้งต่อไปที่คุณจะอ่านนั่นคือสิ่งที่คุณจะเห็นบางครั้งก็มีประโยชน์สำหรับตัวแยกวิเคราะห์ดังที่เป็นอยู่:
  • peek (ดูไบต์โดยไม่ต้องอ่านเพื่อให้ยังคงอยู่ในสตรีมเพื่ออ่านภายหลัง)

สตรีมบางรายการอาจรองรับการอ่าน (ซึ่งในกรณีนี้จะเป็น "อินพุตสตรีม"), การเขียน ("เอาต์พุตสตรีม") หรือทั้งสองอย่าง ไม่สามารถค้นหาสตรีมทั้งหมดได้

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

สตรีมเป็นนามธรรมที่มีประโยชน์เนื่องจากสามารถอธิบายไฟล์ (ซึ่งเป็นอาร์เรย์จริงๆดังนั้นการค้นหาจึงตรงไปตรงมา) แต่ยังรวมถึงอินพุต / เอาต์พุตเทอร์มินัล (ซึ่งไม่สามารถค้นหาได้เว้นแต่จะบัฟเฟอร์) ซ็อกเก็ตพอร์ตอนุกรม ฯลฯ ดังนั้นคุณสามารถเขียนโค้ดที่ระบุว่า ไม่ว่าจะเป็น "ฉันต้องการข้อมูลบางส่วนและฉันไม่สนใจว่าข้อมูลนั้นมาจากที่ใดหรือมาที่นี่ได้อย่างไร" หรือ "ฉันจะสร้างข้อมูลบางส่วนและขึ้นอยู่กับผู้โทรของฉันว่าเกิดอะไรขึ้นกับข้อมูลนั้น" อดีตใช้พารามิเตอร์สตรีมอินพุตส่วนหลังใช้พารามิเตอร์สตรีมเอาต์พุต

การเปรียบเทียบที่ดีที่สุดที่ฉันคิดได้ก็คือกระแสเป็นสายพานลำเลียงที่มาหาคุณหรือนำไปจากคุณ (หรือบางครั้งทั้งสองอย่าง) คุณนำสิ่งต่าง ๆ ออกจากสตรีมอินพุตคุณใส่ข้อมูลลงในสตรีมเอาต์พุต สายพานลำเลียงบางสายที่คุณอาจคิดว่าออกมาจากรูในกำแพง - พวกมันไม่สามารถค้นหาได้การอ่านหรือการเขียนเป็นข้อตกลงเพียงครั้งเดียว สายพานลำเลียงบางส่วนวางอยู่ตรงหน้าคุณและคุณสามารถเคลื่อนย้ายไปมาโดยเลือกตำแหน่งที่คุณต้องการอ่าน / เขียนในสตรีม

ดังที่ IRBMe กล่าวว่าควรคิดถึงสตรีมในแง่ของการดำเนินงานที่เสนอ (ซึ่งแตกต่างกันไปในแต่ละการนำไปใช้งาน แต่มีหลายอย่างที่เหมือนกัน) แทนที่จะเป็นการเปรียบเทียบทางกายภาพ สตรีมคือ "สิ่งที่คุณอ่านหรือเขียนได้" เมื่อคุณเริ่มเชื่อมต่ออะแดปเตอร์สตรีมคุณสามารถคิดว่ามันเป็นกล่องที่มีสายพานลำเลียงเข้าและสายพานลำเลียงออกที่คุณเชื่อมต่อกับสตรีมอื่น ๆ จากนั้นกล่องจะทำการแปลงข้อมูลบางอย่าง (การบีบอัดข้อมูลหรือการเปลี่ยนฟีด UNIX ไปยัง DOS หรืออะไรก็ตาม) ไปป์เป็นการทดสอบอุปมาอุปไมยอย่างละเอียดอีกวิธีหนึ่งนั่นคือจุดที่คุณสร้างสตรีมคู่หนึ่งเพื่อให้ทุกสิ่งที่คุณเขียนลงในหนึ่งสามารถอ่านได้ คิดว่าหนอน :-)


3
คำอธิบายที่ดีที่สุดที่ฉันเคยอ่าน ควบคู่ไปกับสิ่งที่กล่าวใน SICP ("การประมวลผลแบบสตรีมช่วยให้เราจำลองระบบที่มีสถานะโดยไม่ต้องใช้การกำหนดหรือข้อมูลที่เปลี่ยนแปลงได้") คิดว่าในที่สุดฉันก็เข้าใจแล้ว ขอบคุณ!
Kyle Chadha

92

สตรีมเป็นคำอุปมาอุปมัยอยู่แล้วดังนั้นจึงไม่จำเป็นต้องมองข้ามกระแส คุณสามารถคิดว่าโดยพื้นฐานแล้วเป็นท่อที่มีการไหลของน้ำโดยที่น้ำเป็นข้อมูลจริงและท่อก็คือลำธาร ฉันคิดว่ามันเป็นท่อ 2 ทางถ้าสตรีมเป็นแบบสองทิศทาง โดยพื้นฐานแล้วมันเป็นนามธรรมทั่วไปที่วางอยู่บนสิ่งที่มีการไหลหรือลำดับของข้อมูลในทิศทางเดียวหรือทั้งสองทิศทาง

ในภาษาต่างๆเช่น C #, VB.Net, C ++, Java เป็นต้นคำเปรียบเทียบสตรีมใช้สำหรับหลายสิ่ง มีสตรีมไฟล์ที่คุณเปิดไฟล์และสามารถอ่านจากสตรีมหรือเขียนลงในไฟล์ได้อย่างต่อเนื่อง มีสตรีมเครือข่ายที่การอ่านและการเขียนไปยังสตรีมจะอ่านและเขียนไปยังการเชื่อมต่อเครือข่ายที่สร้างขึ้น สตรีมสำหรับการเขียนเท่านั้นที่มักจะเรียกว่ากระแสการส่งออกในขณะนี้เช่นและในทำนองเดียวกันลำธารที่มีการอ่านเพียง แต่จะเรียกว่ากระแสการป้อนข้อมูลในขณะนี้ตัวอย่างเช่น

สตรีมสามารถทำการแปลงหรือเข้ารหัสข้อมูลได้ (เช่นSslStreamใน. Net จะกินข้อมูลการเจรจา SSL และซ่อนจากคุณ TelnetStream อาจซ่อนการเจรจา Telnet จากคุณ แต่ให้การเข้าถึงข้อมูล A ZipOutputStreamใน Java ช่วยให้คุณสามารถเขียนไปยังไฟล์ในไฟล์ zip โดยไม่ต้องกังวลกับรูปแบบไฟล์ zip ภายใน

สิ่งทั่วไปอีกอย่างที่คุณอาจพบคือสตรีมแบบข้อความที่อนุญาตให้คุณเขียนสตริงแทนไบต์หรือบางภาษามีสตรีมไบนารีที่อนุญาตให้คุณเขียนประเภทดั้งเดิมได้ สิ่งทั่วไปที่คุณจะพบในสตรีมข้อความคือการเข้ารหัสอักขระซึ่งคุณควรทราบ

ลำธารบางคนยังสนับสนุนการเข้าถึงแบบสุ่มในขณะนี้ตัวอย่างเช่น ในทางกลับกันสตรีมเครือข่ายด้วยเหตุผลที่ชัดเจนจะไม่ทำเช่นนั้น

  • MSDNให้ภาพรวมที่ดีของสตรีมใน. Net
  • Sun ยังมีภาพรวมของคลาสOutputStreamทั่วไปและคลาสInputStream
  • ใน C ++ นี่คือเอกสารistream (อินพุตสตรีม), ostream (สตรีมเอาต์พุต) และiostream (สตรีมแบบสองทิศทาง)

UNIX เช่นระบบปฏิบัติการยังสนับสนุนรูปแบบสตรีมด้วยการป้อนข้อมูลของโปรแกรมและการส่งออกตามที่อธิบายไว้ที่นี่


13

คำตอบที่ได้รับนั้นยอดเยี่ยมมาก ฉันเพียงแค่ให้ข้อมูลอื่นเพื่อเน้นว่าสตรีมไม่ใช่ลำดับไบต์หรือเฉพาะสำหรับภาษาโปรแกรมเนื่องจากแนวคิดเป็นสากล (ในขณะที่การใช้งานอาจไม่ซ้ำกัน) ฉันมักจะเห็นคำอธิบายมากมายทางออนไลน์ในแง่ของ SQL หรือ C หรือ Java ซึ่งเหมาะสมกับการสตรีมไฟล์ที่เกี่ยวข้องกับตำแหน่งหน่วยความจำและการดำเนินการระดับต่ำ แต่พวกเขามักจะกล่าวถึงวิธีสร้างสตรีมไฟล์และดำเนินการกับไฟล์ที่เป็นไปได้ในภาษาที่กำหนดแทนที่จะพูดถึงแนวคิดของสตรีม

อุปมา

ดังที่ได้กล่าวไปแล้ว a streamเป็นคำเปรียบเทียบซึ่งเป็นนามธรรมของสิ่งที่ซับซ้อนกว่า เพื่อให้จินตนาการของคุณทำงานได้ฉันขอเสนอคำเปรียบเปรยอื่น ๆ :

  1. คุณต้องการเติมน้ำในสระที่ว่างเปล่า วิธีหนึ่งที่จะทำให้สำเร็จได้คือต่อท่อเข้ากับเดือยวางปลายท่อลงในสระแล้วเปิดน้ำ

ท่อเป็นกระแส

  1. ในทำนองเดียวกันหากคุณต้องการเติมน้ำมันในรถคุณต้องไปที่ปั๊มแก๊สใส่หัวฉีดเข้าไปในถังแก๊สแล้วเปิดวาล์วโดยบีบก้านล็อค

ท่อหัวฉีดและกลไกที่เกี่ยวข้องเพื่อให้ก๊าซไหลเข้าสู่ถังของคุณคือกระแส

  1. หากคุณจำเป็นต้องไปทำงานคุณจะเริ่มขับรถจากบ้านไปที่ทำงานโดยใช้ทางด่วน

ทางด่วนคือสายน้ำ

  1. หากคุณต้องการสนทนากับใครสักคนคุณจะใช้หูในการได้ยินและปากของคุณในการพูด

หูและตาของคุณเป็นสายธาร

หวังว่าคุณจะสังเกตเห็นในตัวอย่างเหล่านี้ว่าคำอุปมาอุปมัยของสตรีมมีขึ้นเพื่อให้บางสิ่งบางอย่างสามารถเดินทางผ่านได้ (หรือในกรณีของทางด่วน) และไม่ได้โพสท่าในสิ่งที่กำลังถ่ายโอน ความแตกต่างที่สำคัญ เราไม่ได้หมายถึงหูของเราเป็นลำดับของคำ ท่อยังคงเป็นสายยางหากไม่มีน้ำไหลผ่าน แต่เราต้องต่อเข้ากับเดือยเพื่อให้ทำงานได้อย่างถูกต้อง ไม่ใช่รถยนต์ 'ชนิดเดียว' เพียงชนิดเดียวที่สามารถสัญจรบนทางด่วนได้

ดังนั้นกระแสสามารถอยู่ที่ไม่มีข้อมูลการเดินทางผ่านมันตราบเท่าที่มันจะเชื่อมต่อไปยังไฟล์

การลบ Abstraction

ต่อไปเราต้องตอบคำถามสองสามข้อ ฉันจะใช้ไฟล์เพื่ออธิบายสตรีมดังนั้น ... ไฟล์คืออะไร? แล้วเราจะอ่านไฟล์ได้อย่างไร? ฉันจะพยายามตอบสิ่งนี้ในขณะที่รักษาระดับนามธรรมเพื่อหลีกเลี่ยงความซับซ้อนที่ไม่จำเป็นและจะใช้แนวคิดของไฟล์ที่สัมพันธ์กับระบบปฏิบัติการ linux เนื่องจากความเรียบง่ายและการเข้าถึง

ไฟล์คืออะไร

ไฟล์เป็นนามธรรม :)

หรืออย่างที่ฉันสามารถอธิบายได้ไฟล์คือโครงสร้างข้อมูลส่วนหนึ่งที่อธิบายไฟล์และข้อมูลส่วนหนึ่งซึ่งเป็นเนื้อหาจริง

ส่วนโครงสร้างข้อมูล (เรียกว่าไอโหนดในระบบ UNIX / linux) ระบุข้อมูลที่สำคัญเกี่ยวกับเนื้อหา แต่ไม่รวมเนื้อหา (หรือชื่อของไฟล์สำหรับกรณีนั้น) ข้อมูลส่วนหนึ่งที่เก็บไว้คือที่อยู่หน่วยความจำที่เนื้อหาเริ่มต้น ดังนั้นด้วยชื่อไฟล์ (หรือฮาร์ดลิงก์ในลินุกซ์) ตัวอธิบายไฟล์ (ชื่อไฟล์ตัวเลขที่ระบบปฏิบัติการให้ความสำคัญ) และตำแหน่งเริ่มต้นในหน่วยความจำเราจึงมีสิ่งที่เราสามารถเรียกไฟล์ได้

(สิ่งสำคัญคือ 'ไฟล์' ถูกกำหนดโดยระบบปฏิบัติการเนื่องจากเป็นระบบปฏิบัติการที่ต้องจัดการในที่สุดและใช่ไฟล์มีความซับซ้อนมากขึ้น)

จนถึงตอนนี้ดีมาก แต่เราจะเอาเนื้อหาของไฟล์พูดจดหมายรักถึงพ่อของคุณอย่างไรให้เราพิมพ์

กำลังอ่านไฟล์

หากเราเริ่มต้นจากผลลัพธ์และย้อนกลับไปเมื่อเราเปิดไฟล์บนคอมพิวเตอร์ของเราเนื้อหาทั้งหมดจะถูกสาดบนหน้าจอให้เราอ่าน แต่อย่างไร? เป็นคำตอบที่เป็นระบบมาก เนื้อหาของไฟล์เองเป็นโครงสร้างข้อมูลอื่น สมมติว่าอาร์เรย์ของอักขระ เรายังคิดว่านี่เป็นสตริงได้

แล้วเราจะ 'อ่าน' สตริงนี้ได้อย่างไร? โดยการค้นหาตำแหน่งในหน่วยความจำและวนซ้ำผ่านอาร์เรย์อักขระของเราทีละอักขระจนกว่าจะถึงจุดสิ้นสุดของอักขระไฟล์ กล่าวอีกนัยหนึ่งคือโปรแกรม

กระแสคือ 'สร้าง' เมื่อโปรแกรมของมันจะถูกเรียกว่าและมีหน่วยความจำตำแหน่งที่จะแนบไปกับหรือเชื่อมต่อกับ เช่นเดียวกับตัวอย่างท่อน้ำของเราท่อจะใช้งานไม่ได้หากไม่ได้เชื่อมต่อกับเดือย ในกรณีของสตรีมจะต้องเชื่อมต่อกับไฟล์เพื่อให้มีอยู่

สตรีมสามารถปรับแต่งเพิ่มเติมได้เช่นสตรีมเพื่อรับอินพุตหรือสตรีมเพื่อส่งเนื้อหาไฟล์ไปยังเอาต์พุตมาตรฐาน UNIX / linux เชื่อมต่อและเปิดสตรีมไฟล์ 3 ไฟล์สำหรับเราทันทีโดยไม่ต้องแบ็ต, stdin (อินพุตมาตรฐาน), stdout (เอาต์พุตมาตรฐาน) และ stderr (ข้อผิดพลาดมาตรฐาน) สตรีมสามารถสร้างเป็นโครงสร้างข้อมูลเองหรืออ็อบเจ็กต์ซึ่งช่วยให้เราดำเนินการที่ซับซ้อนมากขึ้นของการสตรีมข้อมูลผ่านสตรีมเช่นการเปิดสตรีมการปิดสตรีมหรือข้อผิดพลาดในการตรวจสอบไฟล์ที่สตรีมเชื่อมต่อ C ++ cinเป็นตัวอย่างของวัตถุสตรีม

แน่นอนว่าถ้าคุณเลือกได้คุณก็เขียนสตรีมของคุณเองได้

คำจำกัดความ

สตรีมเป็นโค้ดที่ใช้ซ้ำได้ซึ่งจะสรุปความซับซ้อนของการจัดการกับข้อมูลในขณะที่ให้การดำเนินการที่เป็นประโยชน์ในการดำเนินการกับข้อมูล


ดังนั้นสตรีมจึงเป็นสื่อกลางในการไหลของข้อมูล จะต้องเชื่อมต่อกับแหล่งที่มาของข้อมูลและสามารถดำเนินการกับตัวเองและข้อมูลที่ไหลผ่านได้
KingBryan

ใช่. เหตุผลเดียวของฉันในการเขียนคำตอบเพิ่มเติมคือการชี้แจงว่าสตรีมสามารถมีอยู่ได้แม้ว่าข้อมูลจะไม่ไหลผ่านก็ตาม ในขณะที่กระแส IRL (ที่มีน้ำและอื่น ๆ ) จะไม่เป็นกระแสเมื่อน้ำหยุดไหลและอาจทำให้เกิดความสับสนเมื่อคิดถึงการเปรียบเทียบ
rekurzion

1
ฉันกำลังเรียนรู้ Java และคำตอบของคุณช่วยให้ฉันเข้าใจ
KingBryan

7

นอกเหนือจากสิ่งที่กล่าวมาข้างต้นแล้วยังมีสตรีมอีกประเภทหนึ่งซึ่งกำหนดไว้ในภาษาการเขียนโปรแกรมเชิงฟังก์ชันเช่น Scheme หรือ Haskell ซึ่งอาจเป็นโครงสร้างข้อมูลที่ไม่มีที่สิ้นสุดซึ่งสร้างขึ้นโดยฟังก์ชันตามความต้องการ


6

การเปรียบเทียบอีกประการหนึ่ง: คุณไม่สามารถว่ายน้ำกับสตรีมได้นั่นเป็นเหตุผลที่คุณสามารถใช้บิตไบต์สตริงหรือวัตถุถัดไปจากสตรีมได้ในขณะที่ข้อมูลที่อ่านแล้วจะถูกลบ ตั๋วเที่ยวเดียว ... หรือโดยพื้นฐานแล้วเป็นเพียงคิวโดยไม่ต้องจัดเก็บความคงอยู่

เราต้องการคิวหรือไม่? คุณตัดสินใจ.


หมายความว่าในกระแสคุณต้องก้าวไปข้างหน้าไม่สามารถถอยหลังได้ นอกจากนี้ข้อมูลก่อนหน้านี้ถูกลบเมื่อคุณไปข้างหน้าซึ่งบันทึกความทรงจำใช่ไหม
มูฮัมหมัดฟาอิซานข่าน

5

คำว่า "สตรีม" ถูกเลือกเพราะมันแสดงถึง (ในชีวิตจริง) ซึ่งมีความหมายคล้ายกันมากกับสิ่งที่เราต้องการจะสื่อเมื่อเราใช้มัน

เริ่มคิดถึงการเปรียบเทียบกับสายน้ำ คุณได้รับการไหลของข้อมูลอย่างต่อเนื่องเช่นเดียวกับน้ำที่ไหลในแม่น้ำอย่างต่อเนื่อง คุณไม่จำเป็นต้องรู้ว่าข้อมูลมาจากไหนและส่วนใหญ่คุณไม่จำเป็นต้องทำ ไม่ว่าจะมาจากไฟล์ซ็อกเก็ตหรือแหล่งอื่น ๆ ก็ไม่สำคัญ (ไม่ควร) จริงๆ คล้ายกับการรับกระแสน้ำโดยที่คุณไม่จำเป็นต้องรู้ว่ามาจากไหน ไม่ว่าจะมาจากทะเลสาบน้ำพุหรือแหล่งอื่น ๆ ก็ไม่สำคัญ (ไม่ควร) จริงๆ แหล่งที่มา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.