เหตุใดจึงเขียนถึง Stream เป็นชิ้น ๆ

ฉันสงสัยว่าเหตุใดตัวอย่างมากมายจึงอ่านอาร์เรย์ไบต์เป็นสตรีมใน chucks และไม่ใช่ทั้งหมดในคราวเดียว ... ฉันรู้ว่านี่เป็นคำถามที่นุ่มนวล แต่ฉันสนใจ

ฉันเข้าใจเล็กน้อยเกี่ยวกับฮาร์ดแวร์และการเติมบัฟเฟอร์อาจขึ้นอยู่กับขนาดมากและคุณคงไม่อยากเขียนลงในบัฟเฟอร์อีกจนกว่าจะถูกล้างไปยังทุกที่ที่ต้องไป ฯลฯ ... แต่ด้วยแพลตฟอร์ม .Net (และอื่น ๆ ภาษาสมัยใหม่) ฉันเห็นตัวอย่างของทั้งสองอย่าง ดังนั้นเมื่อใช้ which และเมื่อใด หรือวินาทีนั้นเป็น no อย่างแน่นอน?

นี่คือสิ่ง (รหัส) ฉันหมายถึง:

var buffer = new byte[4096];

while (true)
{
    var read = this.InputStream.Read(buffer, 0, buffer.Length);

    if (read == 0)
        break;

    OutputStream.Write(buffer, 0, read);
}

ค่อนข้างมากกว่า:

var buffer = new byte[InputStream.Length];

var read = this.InputStream.Read(buffer, 0, buffer.Length);

OutputStream.Write(buffer, 0, read);

ฉันเชื่อว่าทั้งสองถูกกฎหมาย? เหตุใดจึงต้องวุ่นวายกับ while loop (ในสิ่งที่คุณตัดสินใจจัดโครงสร้างมัน)?

ฉันกำลังเล่นเป็นผู้สนับสนุนปีศาจที่นี่ เพราะฉันอยากเรียนรู้ให้มากที่สุดเท่าที่จะทำได้ :)


person tigerswithguitars    schedule 28.11.2012    source แหล่งที่มา


คำตอบ (4)


ในกรณีแรก สิ่งที่คุณต้องมีคือหน่วยความจำ 4kB ในกรณีที่สอง คุณต้องมีหน่วยความจำมากพอกับข้อมูลอินพุตสตรีม หากสตรีมอินพุตเป็น 4GB คุณต้องมี 4GB

คุณคิดว่ามันจะดีหรือไม่หากการคัดลอกไฟล์ต้องใช้ RAM ขนาด 4GB? จะเป็นอย่างไรหากคุณต้องเตรียมดิสก์อิมเมจขนาด 20GB?

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

อย่างไรก็ตาม หากคุณทราบว่าสตรีมอินพุตจะไม่ใหญ่กว่า 4kB แสดงว่าทั้งสองกรณีมีค่าเท่ากัน

person liori    schedule 28.11.2012
comment
กรณีทั่วไป จำนวนที่คุณเก็บไว้ในหน่วยความจำมีความสำคัญมากกว่า ดังนั้นหากคุณเติมบัฟเฟอร์ (สตรีม) ขึ้นไปและไม่เคลื่อนย้าย นั่นถือเป็นเรื่องไม่ดี สมมติว่าเราเอา OutputStream ออกจากสมการและเติม InputStream ด้วย while loop ใช่ไหม? เพราะผมเคยดูมาแล้วเหมือนกันว่ามันจะแย่เหมือนตัวอย่างที่สองหรือเปล่า? - person tigerswithguitars; 28.11.2012
comment
ทุกอย่างขึ้นอยู่กับกรณีเฉพาะของคุณ สิ่งที่คุณต้องการทำ มีอัลกอริธึมที่สามารถทำงานในส่วนเล็กๆ ได้ (คำนวณผลรวมของค่า ค้นหาค่าสูงสุด) และมีอัลกอริธึมที่ต้องการข้อมูลทั้งหมด (เช่น การเรียงลำดับ) ในกรณีที่สองจำเป็นต้องอ่านข้อมูลทั้งหมด ในกรณีแรก—ไม่จริง - person liori; 28.11.2012
comment
เจ๋ง... ดังนั้นมันจึงเป็นแอปพลิเคชั่นเฉพาะ ซึ่งเป็นความคิดหลักของฉัน ฉันคิดว่า... มากกว่าลักษณะของวัตถุในภาษาส่วนใหญ่ ขอบคุณ :) - person tigerswithguitars; 28.11.2012

บางครั้ง InputStream.Length อาจไม่ถูกต้องสำหรับบางแหล่ง เช่น จากการขนส่งทางเน็ต หรือบัฟเฟอร์อาจมีขนาดใหญ่ เช่น อ่านจากไฟล์ขนาดใหญ่ ไอเอ็มโอ.

person Healer    schedule 28.11.2012
comment
นั่นเป็นจุดที่ดีจริงๆ... ฉันไม่ได้คิดถึงความเป็นไปได้นั้นเลย แต่นั่นก็สมเหตุสมผลดี โดยเฉพาะถ้าคุณอยู่ใกล้โลหะและอ่านข้อมูลการรับบัฟเฟอร์! - person tigerswithguitars; 28.11.2012
comment
+1 ... หวังว่ามันจะเป็น + 2 ฉันต้องการยอมรับคำตอบนี้เมื่อคุณใส่สิ่งที่ฉันไม่เคยคิดเลยด้วยวิธีง่ายๆ ซึ่งเจ๋งเสมอ แต่เพื่อประโยชน์ของชุมชน SO วิธีที่ดีที่สุดคือยอมรับคำตอบที่จะเป็นประโยชน์กับคนส่วนใหญ่ - person tigerswithguitars; 28.11.2012

ช่วยปกป้องคุณจากสถานการณ์ที่อินพุตสตรีมของคุณมีความยาวหลายกิกะไบต์

person Joe    schedule 28.11.2012
comment
คุณหมายถึงอะไรโดยการป้องกัน? ทำไมคุณถึงต้องการมัน? - person tigerswithguitars; 28.11.2012
comment
การป้องกัน ตัวอย่างเช่น OutOfMemoryException - person Joe; 28.11.2012
comment
ขวา. หากคุณอ่านไฟล์ เช่น ในหน่วยความจำซึ่งมีมากกว่าที่แอปพลิเคชันจะสามารถเข้าถึงได้ ที่ให้ไว้. แต่นั่นก็เป็นไปได้เมื่อมีข้อมูลจำนวนมาก ดังนั้นความใหญ่ของรูปแบบไม่ได้ป้องกันสิ่งนี้ เพียงแค่ล้างบัฟเฟอร์ลงในสตรีมเอาท์พุตและรีไซเคิล - person tigerswithguitars; 28.11.2012
comment
@tigerswithguitars - ดังนั้นความใหญ่ของรูปแบบจึงไม่ปกป้องสิ่งนี้ - แน่นอนว่าเป็นเช่นนั้น คุณจะต้องมีบัฟเฟอร์ตามขนาดที่กำหนดไว้ (4096) ในตัวอย่างของคุณ แทนที่จะต้องใช้บัฟเฟอร์ซึ่งมีขนาดใหญ่เท่ากับสตรีมอินพุต - person Joe; 28.11.2012
comment
เยี่ยมเลย...แต่คุณจะมีเพียงไฟล์บางส่วนที่คุณต้องการใช่ไหม ดังนั้นคุณจะต้องทำวิศวกรรมซอฟต์แวร์จริง ๆ และตรวจสอบให้แน่ใจว่านี่จะไม่ทำให้โลกล่มสลาย (แอป ed - ตาย)! :ป - person tigerswithguitars; 28.11.2012
comment
@tigerswithguitars แต่คุณมีเพียงไฟล์บางส่วนที่คุณต้องการใช่ไหม - ไม่ คุณจะได้รับไฟล์ทั้งหมดที่ถูกคัดลอกจากอินพุตสตรีมไปยังเอาต์พุตสตรีมทีละชิ้น โดยบังเอิญ ด้วย .NET 4 หรือใหม่กว่า คุณสามารถใช้ InputStream.CopyTo(OutputStream) ซึ่งใช้ขนาดบัฟเฟอร์เริ่มต้น หรือเช่น InputStream.CopyTo(OutputStream, 4096) ซึ่งช่วยให้คุณระบุขนาดบัฟเฟอร์ - person Joe; 28.11.2012

คุณไม่ทราบว่าข้อมูล Read อาจส่งคืนได้มากเพียงใด นี่อาจทำให้เกิดปัญหาด้านประสิทธิภาพที่สำคัญหากคุณกำลังอ่านไฟล์ขนาดใหญ่มาก

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

person Jon B    schedule 28.11.2012