2009-06-17 31 views
6

Tôi có một quy trình chọn một loạt tệp "xml". Lý do tôi đặt xml trong dấu ngoặc kép là văn bản trong tệp không có phần tử gốc tạo thành xml không hợp lệ. Trong quá trình xử lý của tôi, tôi muốn sửa lỗi này và mở mỗi tệp thêm một nút gốc vào đầu và cuối của mỗi tệp, rồi đóng nó lại. Đây là những gì tôi đã có trong tâm trí, nhưng điều này liên quan đến việc mở tập tin, đọc toàn bộ tập tin, gắn thẻ trên các nút, và sau đó viết toàn bộ tập tin ra. Các tệp này có thể có kích thước lớn hơn 20 MB.Thêm văn bản vào đầu và cuối của tệp trong C#

 foreach (FileInfo file in files) 
     { 
      //open the file 
      StreamReader sr = new StreamReader(file.FullName); 

      // add the opening and closing tags 
      string text = "<root>" + sr.ReadToEnd() + "<root>"; 
      sr.Close(); 

      // now open the same file for writing 
      StreamWriter sw = new StreamWriter(file.FullName, false); 
      sw.Write(text); 
      sw.Close(); 
     } 

Bất kỳ đề xuất nào?

+0

Chỉ cần tò mò: Sử dụng một chuỗi ở đây sẽ có hại cho hiệu suất, hoặc là lớp chuỗi C# đủ tốt cho điều này? – schnaader

+0

Lý do chính không sử dụng chuỗi là nó không thay đổi, nghĩa là mỗi lần bạn thêm thứ vào chuỗi, bạn phải tạo một đối tượng String mới. Kể từ khi mã của ông chỉ có 2 concatenations, tôi không thấy bất kỳ lợi thế trong việc sử dụng StringBuilder, nhưng có lẽ tôi đang thiếu một cái gì đó. Như Earwicker lưu ý mặc dù, có một phương pháp tốt hơn. –

+0

Tôi đã xem qua câu hỏi này vì tôi muốn các tệp nhật ký của mình có thông báo mới nhất ở trên cùng. Bây giờ tôi đã di chuyển quá trình ghi vào bảng và sắp xếp theo DateTime .. :) –

Trả lời

3

Tôi không thể nhìn thấy bất kỳ cải tiến thực sự nào về điều này ... đó là một loại bummer. Vì không có cách nào để "dịch chuyển" một tệp, bạn sẽ luôn phải di chuyển các byte trong toàn bộ tệp để chèn bất kỳ thứ gì ở trên cùng.

Bạn có thể tìm thấy một số lợi ích về hiệu suất bằng cách sử dụng luồng thô thay vì StreamReader, vốn thực sự phân tích luồng dưới dạng văn bản.

+0

Hình phạt hiệu suất là toàn bộ tệp đang được tải vào bộ nhớ, sau đó bị loại bỏ. Điểm của luồng là di chuyển một luồng các ký tự từ nơi này đến nơi khác và tránh những tình huống này. Cơ hội tối ưu hóa là sử dụng một tệp cào để ghi đầu tiên mục nhập mới, sau đó phát trực tuyến trong nội dung cũ và cuối cùng hoán đổi tệp đó với tệp gốc.20mb không quá nhiều đối với RAM, nhưng "hoặc nhiều hơn" có thể là. –

15

Để tránh giữ toàn bộ tệp trong bộ nhớ, hãy đổi tên tệp gốc, sau đó mở tệp bằng StreamReader. Sau đó, mở tên tệp gốc bằng StreamWriter để tạo tệp mới.

Viết tiền tố <root> vào tệp, sau đó sao chép dữ liệu theo khối lớn từ trình đọc tới người viết. Khi bạn đã chuyển tất cả dữ liệu, hãy viết lệnh đóng </root> (lưu ý dấu gạch chéo chuyển tiếp nếu bạn muốn nó là XML). Sau đó đóng cả hai tệp và xóa bản gốc đã đổi tên.

char[] buffer = new char[10000]; 

string renamedFile = file.FullName + ".orig"; 
File.Move(file.FullName, renamedFile); 

using (StreamReader sr = new StreamReader(renamedFile)) 
using (StreamWriter sw = new StreamWriter(file.FullName, false)) 
{ 
    sw.Write("<root>"); 

    int read; 
    while ((read = sr.Read(buffer, 0, buffer.Length)) > 0) 
     sw.Write(buffer, 0, read); 

    sw.Write("</root>"); 
} 

File.Delete(renamedFile); 
+1

Đây là một ứng dụng tốt, nhưng nó vẫn đáng chú ý là các đối tượng Stream thô sẽ hoạt động tốt hơn các lớp StreamReader/Writer. –

3

Nếu bạn không muốn làm điều này là C#, nó sẽ dễ dàng xử lý tại dòng lệnh hoặc trong tệp lô.

ECHO ^<root^> > outfile.xml 
TYPE temp.xml >> outfile.xml 
ECHO ^</root^> >> outfile.xml 

Điều này giả định rằng bạn có một số quy trình hiện có để nhận các tệp dữ liệu có thể được nối vào.

+0

Mã để quản lý cuộc gọi đến tệp lô này vào chương trình C# kèm theo có khả năng dài hơn đáng kể so với mã để thực hiện tương tự trực tiếp trong C#. –

+0

Luôn giả định rằng việc xử lý hàng loạt không thể được thêm vào một nơi khác trong quá trình nhận tệp, Process p = Process.Start ("fixup.bat", "temp.xml"); p.WaitForExit(); Dường như không tệ với tôi. Nhấp nháy của cửa sổ lệnh sẽ gây khó chịu. –

+0

Bạn cũng cần phải nói cho tập tin thực thi mà tập tin cần xem, có nghĩa là bạn phải xây dựng chuỗi dòng lệnh, với trích dẫn chính xác, và bạn cần phải tìm ra đường dẫn đến tệp lô và bạn cần xóa các tập tin tạm thời (một dòng, bất cứ nơi nào bạn đặt nó). Tôi ngạc nhiên vì bạn thậm chí còn cân nhắc lựa chọn này! Nó sẽ là tầm thường để viết một số phương pháp trợ giúp nhỏ gọn gàng mà có thể cho phép bạn thể hiện kiểu nối luồng này một cách tao nhã trong C#, và do đó không có quá trình tạo ra quá trình nào cả. –

4

20 MB không quá nhiều, nhưng khi bạn đọc nó dưới dạng chuỗi, nó sẽ sử dụng khoảng 40 MB bộ nhớ. Đó không phải là khủng khiếp nhiều, nhưng nó xử lý mà bạn không cần phải làm. Bạn có thể xử lý nó như byte thô để giảm sử dụng bộ nhớ, và để tránh giải mã và tái mã hóa dữ liệu:

byte[] start = Encoding.UTF8.GetBytes("<root>"); 
byte[] ending = Encoding.UTF8.GetBytes("</root>"); 

byte[] data = File.ReadAllBytes(file.FullName); 

int bom = (data[0] == 0xEF) ? 3 : 0; 

using (FileStream s = File.Create(file.FullName)) { 
    if (bom > 0) { 
     s.Write(data, 0, bom); 
    } 
    s.Write(start, 0, start.Length); 
    s.Write(data, bom, data.Length - bom); 
    s.Write(ending, 0, ending.Length); 
} 

Nếu bạn cần recude sử dụng bộ nhớ nhiều hơn, sử dụng một tập tin thứ hai như Earwicker gợi ý.

Chỉnh sửa:
Đã thêm mã để xử lý BOM (dấu thứ tự byte).

+1

"40 MB bộ nhớ .. Đó không phải là khủng khiếp lắm ... "* ho *. –

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