Maneira mais rápida de adicionar um novo nó ao final de um xml?

Eu tenho um arquivo xml grande (aprox. 10 MB) na seguinte estrutura simples:

 ....... ....... ....... ....... .......  

Minha necessidade é escrever adicionar um novo nó no final antes da tag . Qual é o caminho mais rápido para conseguir isso em .net?

Você precisa usar a técnica de inclusão XML.

Seu error.xml (não muda, apenas um esboço. Usado por analisadores XML para ler):

   ]>  &logrows;  

Seu arquivo errorrows.txt (mudanças, o analisador xml não entende):

 .... .... .... 

Então, para adicionar uma input ao errorrows.txt:

 using (StreamWriter sw = File.AppendText("logerrors.txt")) { XmlTextWriter xtw = new XmlTextWriter(sw); xtw.WriteStartElement("Error"); // ... write error messge here xtw.Close(); } 

Ou você pode até usar o .NET 3.5 XElement e append o texto ao StreamWriter :

 using (StreamWriter sw = File.AppendText("logerrors.txt")) { XElement element = new XElement("Error"); // ... write error messge here sw.WriteLine(element.ToString()); } 

Veja também o artigo da Microsoft Técnicas Eficientes para Modificar Arquivos XML Grandes

Primeiro, eu desqualificaria System.Xml.XmlDocument porque é um DOM que requer análise e construção da tree inteira na memory antes de poder ser anexada. Isso significa que seus 10 MB de texto terão mais de 10 MB de memory. Isso significa que é “intensivo de memory” e “demorado”.

Em segundo lugar, desclassificaria o System.Xml.XmlReader porque ele exige a análise do arquivo inteiro antes de você chegar ao ponto em que você pode anexá-lo. Você teria que copiar o XmlReader em um XmlWriter desde que você não pode modificá-lo. Isso requer a duplicação do seu XML na memory antes que você possa anexá-lo.

A solução mais rápida para XmlDocument e XmlReader seria manipulação de seqüência de caracteres (que possui seus próprios problemas de memory):

 string xml = @"..."; int idx = xml.LastIndexOf(""); xml = xml.Substring(0, idx) + "new error"; 

Cortar a tag final, adicionar o novo erro e adicionar a tag final novamente.

Eu suponho que você poderia ficar louco com isso e truncar seu arquivo por 9 caracteres e anexá-lo. Não teria que ler no arquivo e deixaria o sistema operacional otimizar o carregamento da página (só teria que carregar no último bloco ou algo assim).

 System.IO.FileStream fs = System.IO.File.Open("log.xml", System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite); fs.Seek(-("".Length), System.IO.SeekOrigin.End); fs.Write("new error"); fs.Close(); 

Isso causará um problema se o arquivo estiver vazio ou contiver apenas “ “, sendo que ambos podem ser facilmente verificados.

O caminho mais rápido provavelmente seria um access direto a arquivos.

 using (StreamWriter file = File.AppendText("my.log")) { file.BaseStream.Seek(-"".Length, SeekOrigin.End); file.Write(" New error message."); } 

Mas você perde todos os resources XML agradáveis ​​e pode facilmente corromper o arquivo.

Eu usaria XmlDocument ou XDocument para carregar seu arquivo e, em seguida, manipulá-lo adequadamente.

Eu, então, observaria a possibilidade de armazenar em cache esse XmlDocument na memory para que você possa acessar o arquivo rapidamente.

O que você precisa para a velocidade? Você já tem um gargalo de desempenho ou está esperando um?

Tente isso:

  var doc = new XmlDocument(); doc.LoadXml("This is my first error"); XmlNode root = doc.DocumentElement; //Create a new node. XmlElement elem = doc.CreateElement("error"); elem.InnerText = "This is my error"; //Add the node to the document. if (root != null) root.AppendChild(elem); doc.Save(Console.Out); Console.ReadLine(); 

Como o seu arquivo XML é representado no código? Você usa o System.XML-classs? Nesse caso, você poderia usar XMLDocument.AppendChild.

Veja como fazer isso em C, o .NET deve ser semelhante.

O jogo consiste em pular para o final do arquivo, pular a tag, acrescentar a nova linha de erro e escrever uma nova tag.

 #include  #include  #include  int main(int argc, char** argv) { FILE *f; // Open the file f = fopen("log.xml", "r+"); // Small buffer to determine length of \n (1 on Unix, 2 on PC) // You could always simply hard code this if you don't plan on // porting to Unix. char nlbuf[10]; sprintf(nlbuf, "\n"); // How long is our end tag? long offset = strlen(""); // Add in an \n char. offset += strlen(nlbuf); // Seek to the END OF FILE, and then GO BACK the end tag and newline // so we use a NEGATIVE offset. fseek(f, offset * -1, SEEK_END); // Print out your new error line fprintf(f, "New error line\n"); // Print out new ending tag. fprintf(f, "\n"); // Close and you're done fclose(f); } 

É provável que o método mais rápido esteja lendo no arquivo usando um XmlReader e simplesmente replicando cada nó de leitura para um novo stream usando XmlWriter Quando você chegar ao ponto em que encontrar a tag de fechamento , você precisará output seu elemento adicional antes de continuar o ciclo ‘ler e duplicar’. Desta forma, inevitavelmente, será mais difícil do que ler todo o documento no DOM (class XmlDocument ), mas para grandes arquivos XML, muito mais rápido. É certo que, usando StreamReader / StreamWriter seria um pouco mais rápido ainda, mas muito horrível para trabalhar no código.

O uso de técnicas baseadas em strings (como buscar o final do arquivo e, em seguida, mover para trás o comprimento da tag de fechamento) é vulnerável a variações inesperadas, mas perfeitamente legais, na estrutura do documento.

O documento pode terminar com qualquer quantidade de espaço em branco, para escolher o problema mais provável que você encontrará. Também poderia terminar com qualquer número de comentários ou instruções de processamento. E o que acontece se o elemento de nível superior não for denominado Error ?

E aqui está uma situação que, usando manipulação de strings, falha completamente em detectar:

  ...  

Se você usar um XmlReader para processar o XML, embora ele possa não ser tão rápido quanto ao EOF, ele também permitirá que você lide com todas essas possíveis condições de exceção.