การอ่านไฟล์ข้อความขนาดใหญ่พร้อมสตรีมใน C #


97

ฉันมีงานที่น่ารักในการหาวิธีจัดการไฟล์ขนาดใหญ่ที่โหลดลงในโปรแกรมแก้ไขสคริปต์ของแอปพลิเคชันของเรา (เหมือนกับVBAสำหรับผลิตภัณฑ์ภายในของเราสำหรับมาโครด่วน) ไฟล์ส่วนใหญ่มีขนาดประมาณ 300-400 KB ซึ่งโหลดได้ดี แต่เมื่อพวกเขาไปเกิน 100 MB กระบวนการนี้ก็มีช่วงเวลาที่ยากลำบาก (ตามที่คุณคาดหวัง)

สิ่งที่เกิดขึ้นคือไฟล์ถูกอ่านและถูกส่งไปยัง RichTextBox ซึ่งจะถูกนำทางไป - อย่ากังวลกับส่วนนี้มากเกินไป

นักพัฒนาที่เขียนโค้ดเริ่มต้นเพียงแค่ใช้ StreamReader และทำ

[Reader].ReadToEnd()

ซึ่งอาจใช้เวลาสักพักจึงจะเสร็จสมบูรณ์

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

สมมติฐานบางประการ:

  • ไฟล์ส่วนใหญ่จะมีขนาด 30-40 MB
  • เนื้อหาของไฟล์เป็นข้อความ (ไม่ใช่ไบนารี) บางส่วนเป็นรูปแบบ Unix บางส่วนเป็น DOS
  • เมื่อดึงเนื้อหามาแล้วเราจะหาสิ่งที่ใช้เทอร์มิเนเตอร์
  • ไม่มีใครกังวลเมื่อโหลดเวลาที่ใช้ในการแสดงผลใน richtextbox มันเป็นเพียงการโหลดข้อความเริ่มต้น

ตอนนี้สำหรับคำถาม:

  • ฉันสามารถใช้ StreamReader จากนั้นตรวจสอบคุณสมบัติ Length (ดังนั้น ProgressMax) และออก Read สำหรับขนาดบัฟเฟอร์ที่ตั้งไว้และวนซ้ำในขณะที่วนซ้ำWHILSTภายในโปรแกรมทำงานเบื้องหลังดังนั้นจึงไม่บล็อกเธรด UI หลัก จากนั้นส่ง stringbuilder กลับไปที่เธรดหลักเมื่อเสร็จสิ้น
  • เนื้อหาจะไปที่ StringBuilder ฉันสามารถเริ่มต้น StringBuilder ด้วยขนาดของสตรีมได้หรือไม่หากมีความยาว

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


29
ไฟล์สคริปต์ 30-40MB? ปลาทูศักดิ์สิทธิ์! ฉันเกลียดที่จะต้องตรวจสอบรหัสว่า ...
dthorpe

ฉันรู้ว่าคำถามนี้ค่อนข้างเก่า แต่ฉันพบว่าเมื่อวันก่อนและได้ทดสอบคำแนะนำสำหรับ MemoryMappedFile และนี่เป็นวิธีที่เร็วที่สุด การเปรียบเทียบกำลังอ่านไฟล์ 7,616,939 บรรทัด 345MB ผ่านวิธีการอ่านบรรทัดใช้เวลา 12+ ชั่วโมงบนเครื่องของฉันในขณะที่ดำเนินการโหลดเดียวกันและอ่านผ่าน MemoryMappedFile ใช้เวลา 3 วินาที
csonon

เป็นโค้ดเพียงไม่กี่บรรทัด ดูไลบรารีนี้ฉันใช้เพื่ออ่านไฟล์ขนาดใหญ่ 25gb และอื่น ๆ ด้วย github.com/Agenty/FileReader
Vikash Rathee

คำตอบ:


177

คุณสามารถปรับปรุงความเร็วในการอ่านได้โดยใช้ BufferedStream ดังนี้:

using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {

    }
}

อัพเดทเดือนมีนาคม 2556

ฉันเพิ่งเขียนโค้ดสำหรับการอ่านและการประมวลผล (ค้นหาข้อความใน) ไฟล์ข้อความ 1 GB-ish (ใหญ่กว่าไฟล์ที่เกี่ยวข้องมาก) และได้รับประสิทธิภาพที่เพิ่มขึ้นอย่างมากโดยใช้รูปแบบผู้ผลิต / ผู้บริโภค งานโปรดิวเซอร์อ่านเป็นบรรทัดข้อความโดยใช้BufferedStreamและส่งต่อให้กับงานผู้บริโภคที่แยกจากกันซึ่งทำการค้นหา

ฉันใช้นี่เป็นโอกาสในการเรียนรู้ TPL Dataflow ซึ่งเหมาะมากสำหรับการเข้ารหัสรูปแบบนี้อย่างรวดเร็ว

ทำไม BufferedStream จึงเร็วกว่า

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

อัปเดตเดือนธันวาคม 2557: ไมล์สะสมของคุณอาจแตกต่างกันไป

ตามความคิดเห็น FileStream ควรใช้BufferedStreamภายใน ในตอนที่ให้คำตอบนี้เป็นครั้งแรกฉันได้วัดประสิทธิภาพที่เพิ่มขึ้นอย่างมีนัยสำคัญโดยการเพิ่ม BufferedStream ตอนนั้นฉันกำหนดเป้าหมาย. NET 3.x บนแพลตฟอร์ม 32 บิต วันนี้กำหนดเป้าหมาย. NET 4.5 บนแพลตฟอร์ม 64 บิตฉันไม่เห็นการปรับปรุงใด ๆ

ที่เกี่ยวข้อง

ฉันเจอกรณีที่การสตรีมไฟล์ CSV ขนาดใหญ่ที่สร้างขึ้นไปยังสตรีมการตอบกลับจากการกระทำ ASP.Net MVC นั้นช้ามาก การเพิ่ม BufferedStream ปรับปรุงประสิทธิภาพ 100x ในอินสแตนซ์นี้ สำหรับข้อมูลเพิ่มเติมโปรดดูเอาต์พุตที่ไม่ได้บัฟเฟอร์ช้ามาก


12
Dude, BufferedStream สร้างความแตกต่างทั้งหมด +1 :)
Marcus

2
มีค่าใช้จ่ายในการขอข้อมูลจากระบบย่อย IO ในกรณีของการหมุนดิสก์คุณอาจต้องรอให้แผ่นเสียงหมุนเข้าตำแหน่งเพื่ออ่านข้อมูลชิ้นถัดไปหรือแย่กว่านั้นคือรอให้หัวดิสก์เคลื่อนที่ ในขณะที่ SSD ไม่มีชิ้นส่วนกลไกที่จะทำให้สิ่งต่าง ๆ ทำงานช้าลง แต่ก็ยังมีค่าใช้จ่ายต่อการดำเนินการ IO ในการเข้าถึง สตรีมบัฟเฟอร์อ่านมากกว่าสิ่งที่ StreamReader ร้องขอลดจำนวนการโทรไปยัง OS และท้ายที่สุดจำนวนคำขอ IO แยกต่างหาก
Eric J.

4
จริงๆ? สิ่งนี้ไม่แตกต่างในสถานการณ์ทดสอบของฉัน ตามที่Brad Abramsไม่มีประโยชน์ในการใช้ BufferedStream ผ่าน FileStream
Nick Cox

3
@NickCox: ผลลัพธ์ของคุณอาจแตกต่างกันไปขึ้นอยู่กับระบบย่อย IO ของคุณ บนดิสก์หมุนและตัวควบคุมดิสก์ที่ไม่มีข้อมูลในแคช (และข้อมูลที่ไม่ได้แคชโดย Windows) การเร่งความเร็วนั้นใหญ่มาก คอลัมน์ของ Brad เขียนขึ้นในปี 2004 ฉันได้วัดผลการปรับปรุงที่เกิดขึ้นจริงเมื่อเร็ว ๆ นี้
Eric J.

3
สิ่งนี้ไม่มีประโยชน์ตาม: stackoverflow.com/questions/492283/… FileStream ใช้บัฟเฟอร์ภายในอยู่แล้ว
Erwin Mayer

22

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

using (StreamReader sr = File.OpenText(fileName))
{
    string s = String.Empty;
    while ((s = sr.ReadLine()) != null)
    {
        //do your stuff here
    }
}

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


2
สิ่งนี้ใช้ได้ดีกับการแยกไฟล์ postgres ขนาด 19GB เพื่อแปลเป็นไวยากรณ์ sql ในหลายไฟล์ ขอบคุณคนโพสต์เกรสที่ไม่เคยรันพารามิเตอร์ของฉันอย่างถูกต้อง / ถอนหายใจ
Damon Drake

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

15

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

ถ้าอย่างหลังเป็นจริงการแก้ปัญหาจะง่ายกว่ามาก เพียงทำreader.ReadToEnd()บนเธรดพื้นหลังและแสดงแถบความคืบหน้าแบบกระโจมแทนแถบที่เหมาะสม

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


2
แต่ผู้ใช้สามารถยกเลิกการโทร ReadToEnd ได้หรือไม่?
Tim Scarborough

@ ทิมด่างดี. ในกรณีนี้เรากลับไปที่StreamReaderลูป อย่างไรก็ตามจะยังคงง่ายกว่านี้เนื่องจากไม่จำเป็นต้องอ่านล่วงหน้าเพื่อคำนวณตัวบ่งชี้ความคืบหน้า
Christian Hayter

8

สำหรับไฟล์ไบนารีวิธีที่เร็วที่สุดในการอ่านที่ฉันพบคือสิ่งนี้

 MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(file);
 MemoryMappedViewStream mms = mmf.CreateViewStream();
 using (BinaryReader b = new BinaryReader(mms))
 {
 }

ในการทดสอบของฉันมันเร็วกว่าหลายร้อยเท่า


2
คุณมีหลักฐานที่ยากหรือไม่? เหตุใด OP จึงควรใช้สิ่งนี้กับคำตอบอื่น ๆ โปรดเจาะลึกและให้รายละเอียดอีกเล็กน้อย
Dylan Corriveau

7

ใช้ผู้ทำงานเบื้องหลังและอ่านบรรทัดจำนวน จำกัด เท่านั้น อ่านเพิ่มเติมเมื่อผู้ใช้เลื่อนเท่านั้น

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

คนที่บอกให้คุณใช้ StringBuilder ต้องอ่าน MSDN บ่อยขึ้น:

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

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

ตัวเลือก StringBuilder ดูดีสำหรับผู้ที่ใช้ระบบในฐานะผู้ใช้แบบโมโน แต่เมื่อคุณมีผู้ใช้สองคนขึ้นไปอ่านไฟล์ขนาดใหญ่ในเวลาเดียวกันแสดงว่าคุณมีปัญหา


ไกลออกไปพวกคุณเร็วมาก! น่าเสียดายเนื่องจากวิธีการทำงานของมาโครจำเป็นต้องโหลดสตรีมทั้งหมด ดังที่ได้กล่าวไปแล้วไม่ต้องกังวลกับส่วน richtext มันเป็นการโหลดครั้งแรกที่เราต้องการปรับปรุง
Nicole Lee

เพื่อให้คุณสามารถทำงานเป็นส่วน ๆ อ่าน X บรรทัดแรกใช้มาโครอ่าน X บรรทัดที่สองใช้มาโครและอื่น ๆ ... ถ้าคุณอธิบายว่ามาโครนี้ทำอะไรเราสามารถช่วยคุณได้อย่างแม่นยำมากขึ้น
Tufo

5

นี่น่าจะเพียงพอสำหรับคุณเริ่มต้น

class Program
{        
    static void Main(String[] args)
    {
        const int bufferSize = 1024;

        var sb = new StringBuilder();
        var buffer = new Char[bufferSize];
        var length = 0L;
        var totalRead = 0L;
        var count = bufferSize; 

        using (var sr = new StreamReader(@"C:\Temp\file.txt"))
        {
            length = sr.BaseStream.Length;               
            while (count > 0)
            {                    
                count = sr.Read(buffer, 0, bufferSize);
                sb.Append(buffer, 0, count);
                totalRead += count;
            }                
        }

        Console.ReadKey();
    }
}

4
ฉันจะย้าย "var buffer = new char [1024]" ออกจากลูป: ไม่จำเป็นต้องสร้างบัฟเฟอร์ใหม่ทุกครั้ง ใส่ไว้ก่อนหน้า "while (count> 0)"
Tommy Carlier

4

ดูข้อมูลโค้ดต่อไปนี้ Most files will be 30-40 MBคุณได้กล่าวถึง สิ่งนี้อ้างว่าอ่าน 180 MB ใน 1.4 วินาทีบน Intel Quad Core:

private int _bufferSize = 16384;

private void ReadFile(string filename)
{
    StringBuilder stringBuilder = new StringBuilder();
    FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);

    using (StreamReader streamReader = new StreamReader(fileStream))
    {
        char[] fileContents = new char[_bufferSize];
        int charsRead = streamReader.Read(fileContents, 0, _bufferSize);

        // Can't do much with 0 bytes
        if (charsRead == 0)
            throw new Exception("File is 0 bytes");

        while (charsRead > 0)
        {
            stringBuilder.Append(fileContents);
            charsRead = streamReader.Read(fileContents, 0, _bufferSize);
        }
    }
}

บทความต้นฉบับ


3
การทดสอบประเภทนี้ไม่น่าเชื่อถืออย่างฉาวโฉ่ คุณจะอ่านข้อมูลจากแคชของระบบไฟล์เมื่อคุณทำการทดสอบซ้ำ นั่นคืออย่างน้อยหนึ่งลำดับของขนาดที่เร็วกว่าการทดสอบจริงที่อ่านข้อมูลจากดิสก์ ไฟล์ 180 MB ต้องใช้เวลาไม่น้อยกว่า 3 วินาที รีบูตเครื่องของคุณเรียกใช้การทดสอบหนึ่งครั้งสำหรับจำนวนจริง
Hans Passant

7
บรรทัด stringBuilder.Append อาจเป็นอันตรายคุณต้องแทนที่ด้วย stringBuilder.Append (fileContents, 0, charsRead); เพื่อให้แน่ใจว่าคุณไม่ได้เพิ่มอักขระ 1024 ตัวเต็มแม้ว่าสตรีมจะสิ้นสุดลงก่อนหน้านี้ก็ตาม
Johannes Rudolph

@JohannesRudolph ความคิดเห็นของคุณเพิ่งแก้ไขข้อบกพร่องให้ฉัน คุณคิดเลข 1024 ได้อย่างไร?
OfirD

3

คุณอาจจะดีกว่าที่จะใช้การจัดการไฟล์ที่แมปหน่วยความจำที่นี่ .. การรองรับไฟล์ที่แมปหน่วยความจำจะอยู่ใน. NET 4 (ฉันคิดว่า ... ฉันได้ยินมาว่ามีคนพูดถึงเรื่องนี้) ดังนั้นกระดาษห่อนี้ซึ่งใช้ p / ชวนทำเหมือนเดิม ..

แก้ไข:ดูที่นี่ในMSDNสำหรับวิธีการทำงานนี่คือรายการบล็อกที่ระบุวิธีการดำเนินการใน. NET 4 ที่กำลังจะมาถึงเมื่อออกมาเป็นรุ่น ลิงค์ที่ฉันให้ไว้ก่อนหน้านี้คือ wrapper รอบ pinvoke เพื่อให้บรรลุสิ่งนี้ คุณสามารถแมปไฟล์ทั้งหมดลงในหน่วยความจำและดูได้เหมือนหน้าต่างบานเลื่อนเมื่อเลื่อนดูไฟล์


3

ทุกคำตอบที่ดีเยี่ยม! อย่างไรก็ตามสำหรับคนที่กำลังมองหาคำตอบสิ่งเหล่านี้ดูเหมือนจะไม่สมบูรณ์

เนื่องจากสตริงมาตรฐานสามารถทำได้เฉพาะขนาด X, 2Gb ถึง 4Gb ขึ้นอยู่กับการกำหนดค่าของคุณคำตอบเหล่านี้ไม่สามารถตอบสนองคำถามของ OP ได้อย่างแท้จริง วิธีหนึ่งคือการทำงานกับ List of Strings:

List<string> Words = new List<string>();

using (StreamReader sr = new StreamReader(@"C:\Temp\file.txt"))
{

string line = string.Empty;

while ((line = sr.ReadLine()) != null)
{
    Words.Add(line);
}
}

บางคนอาจต้องการ Tokenise และแยกบรรทัดเมื่อประมวลผล ตอนนี้รายการสตริงสามารถมีข้อความจำนวนมากได้


1

ตัววนซ้ำอาจเหมาะสำหรับงานประเภทนี้:

public static IEnumerable<int> LoadFileWithProgress(string filename, StringBuilder stringData)
{
    const int charBufferSize = 4096;
    using (FileStream fs = File.OpenRead(filename))
    {
        using (BinaryReader br = new BinaryReader(fs))
        {
            long length = fs.Length;
            int numberOfChunks = Convert.ToInt32((length / charBufferSize)) + 1;
            double iter = 100 / Convert.ToDouble(numberOfChunks);
            double currentIter = 0;
            yield return Convert.ToInt32(currentIter);
            while (true)
            {
                char[] buffer = br.ReadChars(charBufferSize);
                if (buffer.Length == 0) break;
                stringData.Append(buffer);
                currentIter += iter;
                yield return Convert.ToInt32(currentIter);
            }
        }
    }
}

คุณสามารถเรียกใช้สิ่งต่อไปนี้:

string filename = "C:\\myfile.txt";
StringBuilder sb = new StringBuilder();
foreach (int progress in LoadFileWithProgress(filename, sb))
{
    // Update your progress counter here!
}
string fileData = sb.ToString();

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

นอกจากนี้เนื่องจากคุณต้องการข้อความเราสามารถใช้ BinaryReader เพื่ออ่านเป็นอักขระได้ซึ่งจะช่วยให้แน่ใจว่าบัฟเฟอร์ของคุณจะเรียงกันอย่างถูกต้องเมื่ออ่านอักขระแบบหลายไบต์ ( UTF-8 , UTF-16เป็นต้น)

ทั้งหมดนี้ทำได้โดยไม่ต้องใช้งานพื้นหลังเธรดหรือเครื่องที่กำหนดเองที่ซับซ้อน


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