2010-10-21 62 views
6

Tôi có tệp văn bản chứa 21000 chuỗi (một dòng mỗi dòng) và 500 MB tệp văn bản khác (mã nguồn thư). Đối với mỗi chuỗi tôi cần phải xác định xem nó có chứa trong bất kỳ tập tin nào không. Tôi đã viết chương trình thực hiện công việc nhưng hiệu quả của nó là khủng khiếp (nó sẽ làm điều đó trong vài ngày, tôi cần phải hoàn thành công việc trong tối đa 5-6 giờ).
Tôi đang viết bằng C#, Visual Studio 2010Tìm kiếm nhiều chuỗi trong nhiều tệp

Tôi có một số câu hỏi liên quan đến vấn đề của mình:
a) Cách tiếp cận nào tốt hơn?

foreach(string s in StringsToSearch) 
{ 
    //scan all files and break when string is found 
} 

hoặc

foreach(string f in Files) 
{ 
    //search that file for each string that is not already found 
} 

b) Là nó tốt hơn để quét một dòng tập tin bằng dòng

StreamReader r = new StreamReader(file); 
while(!r.EndOfStream) 
{ 
    string s = r.ReadLine(); 
    //... if(s.Contains(xxx)); 
} 

hoặc

StreamReader r = new StreamReader(file); 
string s = r.ReadToEnd(); 
//if(s.Contains(xxx)); 

c) có luồng cải thiện hiệu suất và làm thế nào Để làm việc đó?
d) Có phần mềm nào có thể làm điều đó để tôi không phải viết mã của riêng mình không?

+0

làm bạn phải viết chương trình? Bạn có thể sử dụng vòng lặp for có thể tìm kiếm các tệp khác song song –

+0

Chắc chắn không phải là câu trả lời chính xác/đầy đủ, nhưng không tải tất cả (500MB!) tệp cho mỗi chuỗi. Một khi bạn có (một phần của) tập tin trong bộ nhớ, hãy làm tất cả các hành động của bạn sau đó. – Bertvan

+0

Tôi muốn tải toàn bộ tệp một, không phải 500 MB tệp cùng một lúc. – Ichibann

Trả lời

3

Bạn muốn giảm thiểu tệp I/O, vì vậy ý ​​tưởng đầu tiên của bạn rất tệ vì bạn sẽ mở các tệp 'khác' lên tới 21.000 lần. Bạn muốn sử dụng một cái gì đó dựa trên thứ hai (a1). Và khi những tệp khác đó không quá lớn, hãy tải chúng vào bộ nhớ một lần với readAllText.

List<string> keys = ...; // load all strings 

foreach(string f in Files) 
{ 
    //search for each string that is not already found 
    string text = System.IO.File.ReadAllText(f); //easy version of ReadToEnd 


    // brute force 
    foreach(string key in keyes) 
    { 
     if (text.IndexOf(key) >= 0) .... 
    } 

} 

Phần vũ lực có thể được cải thiện nhưng tôi nghĩ bạn sẽ thấy nó có thể chấp nhận được.

+0

Nếu (text.IndexOf (key)> = 0) nhanh hơn if (text.Contains (key))? – Ichibann

+0

@Ichi: Không, tôi cho rằng chúng sẽ nhanh như nhau. –

2
  1. Trong cả hai a) và b), tùy chọn thứ hai là hiệu quả
  2. luồng có thể không cải thiện hiệu suất coz mỗi thread sẽ đọc các tập tin từ đĩa của bạn, do đó, bạn đĩa sẽ trở thành nút cổ chai.
  3. sry tôi không có ý tưởng về s/w cho mục đích của bạn

đoạn chủ đề

 foreach (FileInfo file in FileList) 
     { 
     Thread t = new Thread(new ParameterizedThreadStart(ProcessFileData)); 
     t.Start(file.FullName); 
     }//where processFileData is the method that process the files 

tôi Hướng dẫn chung/O

gì sau đây là một số kiến ​​nghị cơ bản để giảm I/O hoạt động của chương trình của bạn, và do đó tăng cường hiệu suất của nó. Như với tất cả các khuyến nghị, điều quan trọng là đo lường hiệu suất của mã được tối ưu hóa trước và sau khi tối ưu hóa để đảm bảo rằng nó thực sự nhanh hơn.

  1. Giảm thiểu số lượng các tập tin hoạt động bạn thực hiện
  2. Nhóm nhiều giao dịch chuyển nhỏ I/O thành một chuyển nhượng lớn.Một đơn ghi tám trang nhanh hơn tám bài viết riêng lẻ một trang, chủ yếu vì nó cho phép đĩa cứng ghi dữ liệu trong một lần trên bề mặt đĩa. Để biết thêm thông tin ,
  3. Thực hiện lần đọc tuần tự thay vì tìm và đọc các khối nhỏ dữ liệu. Nhân một cách rõ ràng các hoạt động I/O cụm, làm cho số lần truy cập nhanh hơn nhiều.
  4. Tránh bỏ qua trước một tệp trống trước khi ghi dữ liệu. Hệ thống phải ghi số 0 vào số không gian can thiệp để lấp đầy khoảng trống. Để biết thêm thông tin, hãy xem Đọc thường rẻ hơn viết dữ liệu.
  5. Trì hoãn mọi hoạt động I/O cho đến khi chỉ ra rằng ứng dụng của bạn thực sự cần dữ liệu.
  6. Sử dụng hệ thống tùy chọn để chỉ ghi lại tùy chọn người dùng (chẳng hạn làm vị trí cửa sổ và xem cài đặt) và không dữ liệu có thể là .
  7. Đừng cho rằng dữ liệu tệp bộ nhớ đệm trong bộ nhớ sẽ tăng tốc ứng dụng của bạn. Lưu trữ dữ liệu tập tin trong bộ nhớ cải thiện tốc độ cho đến khi bộ nhớ được đổi chỗ ra đĩa, tại mà bạn chỉ trả giá cho truy cập lại vào đĩa. Phấn đấu để tìm một cân bằng hợp lý giữa việc đọc đĩa và bộ nhớ đệm trong bộ nhớ
6

Nếu bạn chỉ muốn biết nếu chuỗi được tìm thấy hoặc không tìm thấy, và không cần phải làm bất cứ tiếp tục xử lý, sau đó tôi khuyên bạn nên sử dụng grep. Grep cực kỳ nhanh và được thiết kế cho chính xác loại vấn đề này.

grep -f strings-file other-files... 

nên thực hiện thủ thuật. Tôi chắc rằng có một triển khai Windows ở đâu đó. Tệ nhất, Cygwin sẽ có nó.

EDIT: Câu hỏi trả lời này d)

+0

Có, mặc dù thẻ [C#] này có thể là cách tiếp cận tốt nhất. –

+0

Tôi không quen với grep và nó hoạt động như thế nào có lẽ ít giúp đỡ làm thế nào để sử dụng? – Ichibann

+0

Grep là một công cụ rất phổ biến trong các hệ thống * nix. Có rất nhiều tài liệu trên mạng để có một hướng dẫn tốt ở đâu đó. Lệnh được đề xuất tìm kiếm tất cả các chuỗi được tìm thấy trong "chuỗi tệp" trong bất kỳ "tệp khác" và in ra tất cả các dòng khớp trong "tệp khác". Có nhiều tùy chọn để thay đổi đầu ra cho những gì bạn cần. –

2

Tìm kiếm có phải là thời gian thực trên 500 MB văn bản hiện tại không? Lý do tôi hỏi là vì bạn có thể xây dựng chỉ mục tìm kiếm trên các tệp văn bản và thực hiện tìm kiếm. Nó sẽ là nhanh hơn nhiều ... Hãy nhìn vào Lucene

Lucene.Net

C# and Lucene to index and search

+0

Không cần tìm kiếm thời gian thực. Đó là nhiệm vụ một lần. Làm và quên nó đi: P – Ichibann

+0

Sau đó sử dụng Lucene (Tôi đã không sử dụng Windows Search SDK) để xây dựng một chỉ mục tìm kiếm đầy đủ và thực hiện tra cứu chống lại nó ... Tôi đã sử dụng Lucene trước ... Thật nhanh! – zam6ak

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