Добавление текста в начало и конец файла в C # - PullRequest
6 голосов
/ 17 июня 2009

У меня есть процесс, который собирает серию файлов "xml". Причина, по которой я помещаю xml в кавычки, состоит в том, что текст в файле не имеет корневого элемента, который делает недействительным xml. В процессе обработки я хочу исправить это и открыть каждый файл, добавить корневой узел в начало и конец каждого файла, а затем закрыть его. Вот что я имел в виду, но это включает в себя открытие файла, чтение всего файла, маркировку на узлах, а затем запись всего файла. Размер этих файлов может превышать 20 МБ.

        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();
        }

Любые рекомендации?

Ответы [ 4 ]

15 голосов
/ 17 июня 2009

Чтобы не хранить весь файл в памяти, переименуйте исходный файл, затем откройте его с помощью StreamReader. Затем откройте исходное имя файла с помощью StreamWriter, чтобы создать новый файл.

Записать префикс <root> в файл, затем скопировать данные большими кусками из считывателя в записывающее устройство. Когда вы перенесли все данные, напишите закрывающий </root> (обратите внимание на косую черту, если вы хотите, чтобы это был XML) Затем закройте оба файла и удалите переименованный оригинал.

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);
4 голосов
/ 17 июня 2009

20 МБ это не очень много, но когда вы читаете его как строку, он использует около 40 МБ памяти. Это тоже не очень много, но это обработка, которую вам не нужно делать. Вы можете обрабатывать его как необработанные байты, чтобы уменьшить использование памяти и избежать декодирования и перекодирования данных:

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);
}

Если вам нужно значительно сократить использование памяти, используйте второй файл, как предложил Earwicker.

Edit:
Добавлен код для обработки спецификации (метка порядка байтов).

3 голосов
/ 17 июня 2009

Если вы не хотите делать это на C #, это будет легко обработать в командной строке или в командном файле.

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

Это предполагает, что у вас есть какой-то существующий процесс для получения файлов данных, к которому это может быть подключено.

3 голосов
/ 17 июня 2009

Я не вижу реального улучшения в этом ... что-то вроде облома. Поскольку нет способа «сдвинуть» файл, вам всегда нужно будет перемещать байты во всем файле, чтобы вставить что-либо вверху.

Вы можете получить некоторое преимущество в производительности, используя необработанные потоки, а не StreamReader, который должен фактически анализировать поток как текст.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...