2012-07-19 52 views
21

thể trùng lặp:
Removing the first line of a text file in C#Di chuyển dòng đầu tiên từ một tập tin

Điều gì sẽ là cách nhanh nhất và thông minh nhất để loại bỏ các dòng đầu tiên từ một khổng lồ (nghĩ 2-3 GB) tập tin?

  • Tôi nghĩ, có thể bạn không thể tránh viết lại toàn bộ tệp theo từng đoạn, nhưng có thể tôi đã sai.

  • Có thể sử dụng các tệp được ánh xạ bộ nhớ bằng cách nào đó giúp giải quyết vấn đề này không?

  • Có thể thực hiện hành vi này bằng cách vận hành trực tiếp trên hệ thống tệp (NTFS chẳng hạn) - hãy cập nhật dữ liệu inode tương ứng và thay đổi ngành bắt đầu tệp để dòng đầu tiên bị bỏ qua? Nếu có, cách tiếp cận này có thực sự mong manh hay có nhiều ứng dụng khác, ngoại trừ chính bản thân số OS làm điều tương tự?

+0

Khi thay đổi dòng đầu tiên, bạn sẽ _have_ để ghi lại các nội dung còn lại. Cân nhắc phân loại tệp ngược lại ... – Oded

+2

Bạn nên gắn thẻ câu hỏi của mình với HĐH và FS đang được đề cập - có thể IS kết hợp hệ thống tệp/os có khả năng CHỈNH SỬA tệp trên đĩa. –

+0

Không có thủ thuật đặc biệt nào. NTFS không hoạt động như thế. – OmnipotentEntity

Trả lời

13

NTFS theo mặc định trên hầu hết các tập (nhưng quan trọng không phải là tất cả!) Lưu trữ dữ liệu trong các khối byte 4096. Chúng được tham chiếu bởi bản ghi $MFT mà bạn không thể chỉnh sửa trực tiếp vì nó không được hệ điều hành (cho các lý do về sự lành mạnh). Kết quả là, không có thủ thuật nào có sẵn để vận hành trên hệ thống tập tin để làm điều gì đó tiếp cận những gì bạn muốn (nói cách khác, bạn không thể trực tiếp đảo ngược cắt bớt một tập tin trên NTFS, ngay cả trong số lượng tệp hệ thống có kích thước.)

Vì cách các tập tin được lưu trữ trong một hệ thống tập tin, câu trả lời duy nhất là bạn phải viết lại toàn bộ tập tin trực tiếp. Hoặc tìm ra một cách khác để lưu trữ dữ liệu của bạn. một tập tin 2-3GB là lớn và điên rồ, đặc biệt là xem xét bạn đề cập đến dòng có nghĩa là dữ liệu này là ít nhất trong phần thông tin văn bản.

Bạn nên xem xét việc đưa dữ liệu này vào cơ sở dữ liệu? Hoặc tổ chức nó hiệu quả hơn một chút ít nhất.

+1

[Bạn có thể sử dụng tệp thưa thớt. ] (http://blogs.msdn.com/b/oldnewthing/archive/2010/12/01/10097859.aspx) – Joey

6

Thậm chí nếu bạn có thể xóa khối hàng đầu thì ít nhất nó cũng là một sector (512 byte), có thể không khớp với kích thước của đường kẻ.

Hãy xem xét một trình bao bọc (thậm chí có thể là tệp trợ giúp) để bắt đầu đọc từ một khoảng bù nhất định.

3

Idea (không bụi ma thuật, chỉ khó làm việc dưới đây):

sử dụng sử dụng chế độ hệ thống tập tin như http://www.eldos.com/cbfs/ hoặc http://dokan-dev.net/en/ để quấn xung quanh hệ thống tập tin thực sự của bạn, và tạo ra một hệ thống sổ sách kế toán nhỏ để theo dõi bao nhiêu của tập tin là 'ăn' ở phía trước. Tại thời điểm nhất định, khi tệp phát triển quá lớn, hãy ghi lại tệp vào tệp khác và bắt đầu lại.

Làm thế nào về điều đó?

EDIT:

nếu bạn đi với hệ thống tập tin ảo, sau đó bạn có thể sử dụng mảnh vỡ (256MB) tập tin nhỏ hơn mà bạn có thể dán vào một tập tin 'ảo' với mong muốn bù đắp. Bằng cách đó bạn sẽ không bao giờ cần phải viết lại tệp.

THÊM:

Reflection trên ý tưởng về 'ghi đè' vài dòng đầu tiên với 'không có gì' - không làm được điều đó, thay vào đó, thêm một 64-bit số nguyên vào phía trước của tập tin, và sử dụng bất kỳ phương pháp bạn muốn bỏ qua nhiều byte, ví dụ: Stream dẫn xuất sẽ quấn luồng gốc và bù đắp việc đọc trong đó.

Tôi đoán điều đó có thể tốt hơn nếu bạn chọn sử dụng trình bao bọc ở phía 'ứng dụng khách'.

8

Bạn có thể ghi đè mọi ký tự mà bạn muốn xóa bằng '\x7f'. Sau đó, khi đọc trong tập tin, người đọc của bạn bỏ qua nhân vật đó. Điều này giả định rằng bạn có một tệp văn bản không bao giờ sử dụng ký tự DEL, tất nhiên.

std::istream & 
my_getline (std::istream &in, std::string &s, 
      char del = '\x7f', char delim = '\n') { 
    std::getline(in, s, delim); 
    std::size_t beg = s.find(del); 
    while (beg != s.npos) { 
     std::size_t end = s.find_first_not_of(del, beg+1); 
     s.erase(beg, end-beg); 
     beg = s.find(del, beg+1); 
    } 
    return in; 
} 

Khi Henk chỉ ra, bạn có thể chọn một nhân vật khác làm DELETE. Tuy nhiên, lợi thế là kỹ thuật này hoạt động bất kể bạn muốn loại bỏ dòng nào (nó không bị giới hạn ở dòng đầu tiên), và không yêu cầu sử dụng hệ thống tệp.

Sử dụng trình đọc đã sửa đổi, bạn có thể định kỳ "chống phân mảnh" tệp. Hoặc, quá trình chống phân mảnh có thể xảy ra một cách tự nhiên khi nội dung được truyền trực tuyến/hợp nhất thành một tệp khác hoặc được lưu trữ vào một máy khác.

Chỉnh sửa: Bạn không nói rõ, nhưng tôi đoán đây là một số loại ứng dụng ghi nhật ký, trong đó mục tiêu là đặt giới hạn trên vào kích thước tệp nhật ký. Tuy nhiên, nếu đó là mục tiêu, sẽ dễ dàng hơn nhiều khi chỉ sử dụng một tập hợp các tệp nhật ký nhỏ hơn. Giả sử bạn duy trì khoảng 10MB tệp nhật ký, với tổng số nhật ký bị chặn đến 4GB. Vì vậy, đó sẽ là khoảng 400 tập tin. Nếu tập tin 401st được bắt đầu, đối với mỗi dòng được viết ở đó, bạn có thể sử dụng điểm đánh dấu DELETE trên các dòng liên tiếp trong tệp đầu tiên. Khi tất cả các dòng đã được đánh dấu để xóa, bản thân tệp có thể bị xóa, để lại cho bạn khoảng 400 tệp một lần nữa. Không có hành vi O (n) bị ẩn, miễn là tệp đầu tiên không bị đóng trong khi các dòng đang bị xóa.

Nhưng vẫn dễ dàng hơn cho phép hệ thống ghi nhật ký giữ nguyên tệp 1 và 401st và xóa tệp thứ nhất khi di chuyển đến tệp 402.

+1

Vâng, ý tưởng thông minh. Ngoài ra, hãy ghi đè lên dấu cách, dòng mới hoặc '\ 0'. Tất cả phụ thuộc vào người đọc mặc dù, và bao nhiêu nó có thể được điều chỉnh. –

+0

@ HenkHolterman: Bạn nói đúng. Tôi đã cập nhật bài đăng để phản ánh rằng một nhân vật khác có thể được chọn. Trân trọng – jxh

0

Chia nhỏ tệp thành hai, tệp đầu tiên là đoạn nhỏ hơn. Xóa dòng đầu tiên và sau đó đính kèm với dòng đầu tiên.

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