2011-07-28 45 views
12

Làm thế nào tôi có thể đọc một tập tin tùy ý và xử lý nó "từng mảnh" (nghĩa là byte theo byte hoặc một số kích thước đoạn khác sẽ cho hiệu suất đọc tốt nhất) mà không tải toàn bộ tệp vào bộ nhớ? Một ví dụ về xử lý sẽ là tạo ra một băm MD5 của tập tin mặc dù câu trả lời có thể áp dụng cho bất kỳ hoạt động nào.Làm cách nào để đọc/phát tệp mà không tải toàn bộ tệp vào bộ nhớ?

Tôi muốn có hoặc viết điều này nhưng nếu tôi có thể nhận được mã hiện tại cũng sẽ tuyệt vời.

(C#)

+1

Hãy nhìn xem, câu trả lời thực sự là "' System.IO.FileStream' KHÔNG tải tệp vào bộ nhớ. " – Vercas

Trả lời

17

Dưới đây là một ví dụ về làm thế nào để đọc một tập tin trong khối 1KB mà không cần tải toàn bộ nội dung vào bộ nhớ:

const int chunkSize = 1024; // read the file by chunks of 1KB 
using (var file = File.OpenRead("foo.dat")) 
{ 
    int bytesRead; 
    var buffer = new byte[chunkSize]; 
    while ((bytesRead = file.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     // TODO: Process bytesRead number of bytes from the buffer 
     // not the entire buffer as the size of the buffer is 1KB 
     // whereas the actual number of bytes that are read are 
     // stored in the bytesRead integer. 
    } 
} 
+0

Vui lòng làm rõ lý do tại sao mã này không đọc tệp hoàn toàn vào bộ nhớ. Ngoài ra, vui lòng giải thích phần TODO của bạn. – Matt

+3

Điều này tải 1KB (hoặc chunkSize byte) vào bộ nhớ. Chỉnh sửa: Ông cũng có nghĩa là không phải toàn bộ 'bộ đệm' được viết! Chỉ các byte từ chỉ mục 0 đến chỉ mục 'bytesRead'. – Vercas

+0

Chết tiệt, ý tôi là từ chỉ mục 0 đến chỉ mục 'bytesRead - 1'. Các bạn, chú ý hơn! – Vercas

9

System.IO.FileStream không tải tệp vào bộ nhớ.
Luồng này có thể tìm kiếm được và thuật toán băm MD5 không phải tải bộ nhớ giới thiệu luồng (tệp).

Vui lòng thay thế file_path bằng đường dẫn đến tệp của bạn.

byte[] hash = null; 

using (var file = new FileStream(file_path, FileMode.Open)) 
{ 
    using (var md5 = new System.Security.Cryptography.MD5CryptoServiceProvider()) 
    { 
     hash = md5.ComputeHash(stream); 
    } 
} 

Ở đây, MD5 Hash của bạn sẽ được lưu trữ trong biến số hash.

+0

Tôi đã không nhận ra ComputeHash có thể lấy một luồng, cảm ơn. Ngoài ra tôi đã thực hiện một số chỉnh sửa. – Howiecamp

+0

@Howiecamp bạn được chào đón! – Vercas

+0

Đối với các ngăn xếp trong tương lai, bạn chỉ cần một câu lệnh sử dụng - nếu tôi nhớ chính xác chúng có thể được nhóm lại với nhau. –

2
const int MAX_BUFFER = 1024; 
byte[] Buffer = new byte[MAX_BUFFER]; 
int BytesRead; 
using (System.IO.FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 
    while ((BytesRead = fileStream.Read(Buffer, 0, MAX_BUFFER)) != 0) 
    { 
     // Process this chunk starting from offset 0 
     // and continuing for bytesRead bytes! 
    } 
3
int fullfilesize = 0;// full size of file 
    int DefaultReadValue = 10485760; //read 10 mb at a time 
    int toRead = 10485760; 
    int position =0; 

    // int 
// byte[] ByteReadFirst = new byte[10485760]; 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     using (var fs = new FileStream(@"filepath", FileMode.Open, FileAccess.Read)) 
     { 
      using (MemoryStream requestStream = new MemoryStream()) 
      { 


       fs.Position = position; 

       if (fs.Position >= fullfilesize) 
       { 
        MessageBox.Show(" all done"); 
        return; 
       } 
       System.Diagnostics.Debug.WriteLine("file position" + fs.Position); 

       if (fullfilesize-position < toRead) 
       { 
        toRead = fullfilesize - position; 
        MessageBox.Show("last time"); 
       } 
       System.Diagnostics.Debug.WriteLine("toread" + toRead); 
       int bytesRead; 
       byte[] buffer = new byte[toRead]; 
       int offset = 0; 
       position += toRead; 
       while (toRead > 0 && (bytesRead = fs.Read(buffer, offset, toRead)) > 0) 
       { 
        toRead -= bytesRead; 
        offset += bytesRead; 
       } 

       toRead = DefaultReadValue; 


      } 
     } 
    } 

Sao chép Darin của, phương pháp này sẽ đọc khối 10mb đến cuối cùng của tập tin

+0

Mặc dù MemoryStream trong ví dụ của bạn là không cần thiết, bạn là người duy nhất đăng một ví dụ nơi bạn thiết lập vị trí FileStream. Điều này đã giải quyết được vấn đề của tôi khi tôi cần chia nhỏ và chuyển các tệp lớn trong các khối 10 megabyte. Đã bỏ phiếu! – DragonZero

0
const long numberOfBytesToReadPerChunk = 1000;//1KB 
using (BinaryReader fileData = new BinaryReader(File.OpenRead(aFullFilePath)) 
    while (fileData.BaseStream.Position - fileData.BaseStream.Length > 0) 
     DoSomethingWithAChunkOfBytes(fileData.ReadBytes(numberOfBytesToReadPerChunk)); 

Theo tôi được biết các chức năng sử dụng ở đây (đặc biệt là BinaryReader.ReadBytes), thứ ere là không cần phải theo dõi có bao nhiêu byte bạn đã đọc. Bạn chỉ cần biết độ dài và vị trí hiện tại của vòng lặp while - luồng đó cho bạn biết.

Các vấn đề liên quan