2011-01-23 21 views
10

Tôi có một cấu trúc XML rất cơ bản/tập tin trên đĩa mà là một cái gì đó như:Trong C#, có cách nào để thêm một nút XML vào một tệp trên đĩa KHÔNG tải nó trước không?

<root> 
    <data timestamp="dd-mm-yyyy" type="comment">kdkdkdk</data> 
    <data timestamp="dd-mm-yyyy" type="event">kdkdkdkgffgfdgf</data> 
    <data timestamp="dd-mm-yyyy" type="something">kddsdsfsdkdkdk</data> 
</root> 

XML sẽ được, như đã đề cập, trong một tập tin bên ngoài trên đĩa. Vì tệp có thể phát triển khá lớn (thực sự bị 'cắt xén' vài tuần một lần), tôi không muốn tải tệp XML trước để thêm nút mới ...

Có cách nào để thêm mới không nút như thế này? nó có thể được thêm vào đầu/cuối v.v., vì quá trình thực sự sử dụng XML sắp xếp nó theo dấu thời gian anyway ..

Tôi đoán một cách thô lỗ là nối thêm nút dưới dạng văn bản .. tuy nhiên tôi nghĩ có thể thêm nút SAU KHI thẻ kết thúc ??

Bất kỳ ý tưởng nào biết ơn đã nhận được .. David.

Trả lời

2

Có một số câu trả lời hợp lý ở đây rồi, tuy nhiên chỉ cần đặt một vòng quay khác về điều này, bạn có chắc dữ liệu này cần được lưu trữ dưới dạng tệp XML không?

Dữ liệu bạn lưu trữ trông khá đơn giản (tức là bản ghi có ba trường, ngày, loại và một số dữ liệu chuỗi. Nếu bạn không cần bất kỳ lợi ích bổ sung nào mà XML cung cấp (see here) thì tại sao không sử dụng cơ bản CSV? bằng cách đó bạn có thể chỉ cần giữ phụ thêm để nó giống như một tập tin đăng nhập qua File.AppendText("filename").

(Hell, nó thậm chí có thể có thể sử dụng một cái gì đó giống như log4net để quản lý khai thác gỗ và bất kỳ dọn dẹp vệ sinh.)

+0

Có, đây có thể là một cách hợp lý để tránh được vấn đề. –

+0

Cảm ơn, thực sự với mọi người, một số hiểu biết tốt cho chắc chắn. Một trong những lý do duy nhất để sử dụng XML (và thực tế nó đã có một số hệ thống ống nước trong một hệ thống hiện có) là có thể tải XML trực tiếp vào tập dữ liệu/bảng để sử dụng với một số mã hiện có. từ câu hỏi này và độ trễ tôi có để tải dữ liệu sau, tùy chọn CSV có thể là cách .. (mặc dù tùy chọn stream.position của Henk cũng không quá tệ!) cảm ơn !! –

4

Bằng cách nào đó, bạn sẽ phải đọc tệp XML vì bạn không thể chỉ thêm nút vào tài liệu.

Tệp Xml chỉ có thể có một gốc, do đó, nút mới sẽ phải được thêm sau phần tử dữ liệu cuối cùng, nhưng trước thẻ đóng gốc. Nếu không, xml không hợp lệ.

+0

Có đúng .. Tôi nhận ra rằng có lẽ sẽ là trường hợp .. nhưng nghĩ tại sao không hỏi câu hỏi nào! chỉ trong trường hợp! –

-3

chỉ cần sử dụng

string s = File.ReadAllText(path) 
s = s.replace("</root>", newnode + "</root>") 
File.WriteAllText(s, path) 
+0

Điều đó vẫn tải nó ... Nó chỉ bỏ qua phân tích cú pháp XML, tiết kiệm nhỏ. I/O đắt tiền. –

+0

Cool .. cách đơn giản để thêm nút mới .. Tôi đoán nó vẫn có nghĩa là đọc tập tin xml, nhưng sau đó tôi đoán nó sẽ là trường hợp, vì vậy cảm ơn cho rằng, ví dụ sạch đẹp! –

+0

-1. Câu hỏi đặt ra là mở các tệp lớn. Tôi không chắc chắn nếu tải một tập tin lớn trong bộ nhớ là một cách tiếp cận tốt nhất, khi có dòng cho điều đó. –

8

Không phải với bất kỳ API XML hoặc công cụ.

Bạn có thể mở tệp dưới dạng Văn bản, tìm Vị trí của </root> và bắt đầu ghi đè từ đó. Và tất nhiên hãy thêm lại </root>.


Một cách tiếp cận nhanh chóng và dơ bẩn, điều này không phải là rất mạnh mẽ:

  • chắc chắn rằng bạn chuẩn bị hồ sơ ban đầu, cần có (không khoảng trắng) sau thẻ đóng
  • đảm bảo bạn sử dụng mã hóa ASCII hoặc UTF8

====

string closeTag = "</root>"; 
int closeLength = Encoding.UTF8.GetBytes(closeTag).Length; 

var fs = System.IO.File.Open(filename, System.IO.FileMode.Open); 
fs.Position = fs.Length - closeLength; 

var writer = new StreamWriter(fs); // after the Position is set 

writer.WriteLine(newTag); 
writer.Write(closeTag); // NOT WriteLine !! 

writer.Close(); 
fs.Close(); 

Và tất nhiên bạn biết cách sử dụng các khối using() {}.

+0

Có đúng .. trong thực tế amcashcow chỉ nhận xét ở trên về điều đó .. vì vậy cảm ơn bạn! –

+0

@David: KHÔNG, tôi muốn nói _not_ đọc tất cả nhưng sử dụng Stream.Position. –

+0

Bạn có thể làm điều đó với một API XML (XmlReader/XmlWriter). Nó không dễ thực hiện (tùy thuộc vào nội dung có thể có của tệp XML), nhưng có thể thực hiện được. Nếu bạn chỉ có các thẻ và thuộc tính cơ bản như trên, thì thậm chí sẽ không khó. – TToni

1

Tùy thuộc.

Nếu bạn muốn thực hiện theo cách "đúng", bạn phải đọc tệp và XML trong đó. Bạn có thể tránh tải nó hoàn toàn vào bộ nhớ bằng cách sử dụng một lớp XmlReader chẳng hạn. Tuy nhiên, nếu bạn hoàn toàn biết bố cục văn bản và mã hóa tệp, bạn có thể tránh đọc và viết lại hoàn toàn bằng cách mở tệp đó dưới dạng tệp truy cập ngẫu nhiên (FileStream), bỏ qua đến cuối (trừ đi "< root />"), thêm mục mới vào đó và viết lại "< root />".

1

Tôi không thể thấy cách để làm những gì bạn đang làm mà không đọc toàn bộ tệp, nhưng có thể bạn có thể xử lý tệp dưới dạng văn bản thuần túy không có nút gốc (nó sẽ là XML không hợp lệ). Sau đó, bạn chỉ có thể nối thêm các nút mới vào tệp dưới dạng văn bản thuần túy.Và vì quá trình phân tích cú pháp XML của bạn tải toàn bộ tệp, nên nó có thể thêm nút gốc trước khi xử lý nó dưới dạng XML.

1
System.IO.FileInfo[] aryFi = di.GetFiles("*.xml"); 


foreach (System.IO.FileInfo fi in aryFi) { 

System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument(); 
xmlDocument.Load(fi.FullName); 

XmlNode refelem = xmlDocument.LastChild; 
XmlNode newElem = xmlDocument.CreateNode("element", "something", ""); 
newElem.InnerText = "sometext"; 
xmlDocument.InsertAfter(newElem, refelem); 
} 

Tôi tin rằng việc mở và chèn một nút sẽ là lựa chọn tốt nhất. Dù bằng cách nào bạn cũng có thể ld cần phải sử dụng IO, tại sao không làm theo cách thích hợp?

Đối với tập tin duy nhất

System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument(); 
xmlDocument.Load("file path"); 

XmlNode refelem = xmlDocument.LastChild; 
XmlNode newElem = xmlDocument.CreateNode("element", "something", ""); 
newElem.InnerText = "sometext"; 
xmlDocument.InsertAfter(newElem, refelem); 
+0

Điều đó '* .xml' dường như đến từ hư không. Và điều này vẫn tải toàn bộ tập tin (và một số khác), câu hỏi là về việc tránh điều đó. –

+0

Có nghĩa là nếu bạn muốn thực hiện cùng một hành động trên tất cả các tệp xml trong một thư mục. Có mã trước đó mà được thông tin thư mục. Trong trường hợp của bạn, bạn sẽ không được lặp qua tất cả các tập tin. Tôi sẽ thêm mã cho một tập tin. – Ismail

+0

Nếu tôi ở trong tình huống này và vì cả hai cách tiếp cận yêu cầu bạn thực hiện cuộc gọi IO thì ưu tiên cho tôi là thêm nút XML thay vì văn bản, bạn có thể có một số lý do để lên kế hoạch thực hiện theo cách này. – Ismail

1

Nếu bằng cách không tải XML, bạn có nghĩa là không xây dựng một cây DOM, VTD-XML là API duy nhất cho phép bạn cắt dán tách hoặc sửa đổi từng bước. Hơn nữa, vì VTD-XML là hiệu quả bộ nhớ, bạn sẽ không phải lo lắng về kích thước của tài liệu XML. Một bài đăng tương tự trong Java là How to update large XML file. Lưu ý rằng vtd-xml có sẵn trong Java, C#, C và C++.

+0

OK, tôi cho rằng tên người dùng của bạn được tính là tiết lộ. –

+0

Đã không nghe nói về điều này .. trên thực tế có thể overkill cho giải pháp này có lẽ, nhưng chắc chắn sẽ kiểm tra nó ra .. –

+0

@ Henk: Tôi không đồng ý, và đã được spam-flagging anh ta (trừ một câu trả lời mà tôi upvoted). –

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