Подтвердить что ты не робот

С#: предварительная подготовка к началу файла

Каков наилучший способ добавить текст в начало файла с помощью С#?

Я не мог найти простой способ сделать это, но придумал пару обходов.

  • Откройте новый файл, напишите текст, который я хотел добавить, добавьте текст из старого файла в конец нового файла.

  • Поскольку текст, который я хочу добавить, должен быть меньше 200 символов, я думал, что могу добавить символы пробела в начало файла, а затем переписать пробел с текстом, который я хотел добавить.

Кто-нибудь еще сталкивается с этой проблемой, и если да, что вы сделали?

4b9b3361

Ответ 1

Добавление в начало файла (добавление в отличие от добавления) обычно не поддерживается. Ваши # 1 варианты в порядке. Если вы не можете написать временный файл, вы можете вытащить весь файл в память, предварите свои данные в массив байтов и затем перезапишите его обратно (это реально реально, если ваши файлы невелики, и вам не нужно имеют кучу в памяти сразу, потому что добавление массива не обязательно легко без копирования).

Ответ 2

Это работает для меня, но для небольших файлов. Вероятно, это не очень хорошее решение.

string currentContent = String.Empty;
if (File.Exists(filePath))
{
    currentContent = File.ReadAllText(filePath);
}
File.WriteAllText(filePath, newContent + currentContent );

Ответ 3

Я думаю, что лучший способ - создать временный файл. Добавьте текст, затем прочитайте содержимое исходного файла, добавив его в файл temp. Затем вы можете перезаписать оригинал временным файлом.

Ответ 4

Вы можете сделать это, не открывая новый файл. Используйте следующий метод File:

public static FileStream Open(
    string path,
    FileMode mode,
    FileAccess access
)

Обязательно укажите FileAccess.ReadWrite.

Используя FileStream, возвращенный из File.Open, прочитайте все существующие данные в памяти. Затем reset указатель на начало файла, напишите новые данные, затем запишите существующие данные.

(Если файл большой и/или вы подозрительно относитесь к использованию слишком большого объема памяти, вы можете сделать это, не прочитав весь файл в памяти, но его реализация останется в качестве упражнения для читателя.)

Ответ 5

// The file we'll prepend to
string filePath = path + "\\log.log";

// A temp file we'll write to
string tempFilePath = path + "\\temp.log";

// 1) Write your prepended contents to a temp file.
using (var writer = new StreamWriter(tempFilePath, false))
{
    // Write whatever you want to prepend
    writer.WriteLine("Hi");
}

// 2) Use stream lib methods to append the original contents to the Temp
// file.
using (var oldFile = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read))
{
    using (var tempFile = new FileStream(tempFilePath, FileMode.Append, FileAccess.Write, FileShare.Read))
    {
        oldFile.CopyTo(tempFile);
    }
}

// 3) Finally, dump the Temp file back to the original, keeping all its
// original permissions etc.
File.Replace(tempFilePath, filePath, null);

Даже если то, что вы пишете, невелико, файл Temp получает весь исходный файл, добавленный к нему перед .Replace(), поэтому он должен быть на диске.

Обратите внимание, что этот код не является потокобезопасным; если более чем один поток обращается к этому коду, вы можете потерять записи в процессе обмена файлами. Тем не менее, это также довольно дорого, поэтому вам все равно нужен доступ к шлюзу - передайте записи через несколько провайдеров в буфер, который периодически выгружается через этот метод prepend для одного потока Consumer.

Ответ 6

Да, в основном вы можете использовать что-то вроде этого:

public static void PrependString(string value, FileStream file)
{
     var buffer = new byte[file.Length];

     while (file.Read(buffer, 0, buffer.Length) != 0)
     {
     }

     if(!file.CanWrite)
         throw new ArgumentException("The specified file cannot be written.", "file");

     file.Position = 0;
     var data = Encoding.Unicode.GetBytes(value);
     file.SetLength(buffer.Length + data.Length);
     file.Write(data, 0, data.Length);
     file.Write(buffer, 0, buffer.Length);
 }

 public static void Prepend(this FileStream file, string value)
 {
     PrependString(value, file);
 }

Тогда

using(var file = File.Open("yourtext.txt", FileMode.Open, FileAccess.ReadWrite))
{
    file.Prepend("Text you want to write.");
}

Не очень эффективен, хотя в случае огромных файлов.

Ответ 7

Используйте этот класс:

public static class File2
{
    private static readonly Encoding _defaultEncoding = new UTF8Encoding(false, true); // encoding used in File.ReadAll*()
    private static object _bufferSizeLock = new Object();
    private static int _bufferSize = 1024 * 1024; // 1mb
    public static int BufferSize 
    {
        get
        {
            lock (_bufferSizeLock)
            {
                return _bufferSize;
            }
        }
        set
        {
            lock (_bufferSizeLock)
            {
                _bufferSize = value;
            }
        }
    }

    public static void PrependAllLines(string path, IEnumerable<string> contents)
    {
        PrependAllLines(path, contents, _defaultEncoding);
    }

    public static void PrependAllLines(string path, IEnumerable<string> contents, Encoding encoding)
    {
        var temp = Path.GetTempFileName();
        File.WriteAllLines(temp, contents, encoding);
        AppendToTemp(path, temp, encoding);
        File.Replace(temp, path, null);
    }

    public static void PrependAllText(string path, string contents)
    {
        PrependAllText(path, contents, _defaultEncoding);
    }

    public static void PrependAllText(string path, string contents, Encoding encoding)
    {
        var temp = Path.GetTempFileName();
        File.WriteAllText(temp, contents, encoding);
        AppendToTemp(path, temp, encoding);
        File.Replace(temp, path, null);
    }

    private static void AppendToTemp(string path, string temp, Encoding encoding)
    {
        var bufferSize = BufferSize;
        char[] buffer = new char[bufferSize];

        using (var writer = new StreamWriter(temp, true, encoding))
        {
            using (var reader = new StreamReader(path, encoding))
            {
                int bytesRead;
                while ((bytesRead = reader.ReadBlock(buffer,0,bufferSize)) != 0)
                {                   
                    writer.Write(buffer,0,bytesRead);
                }
            }
        }
    }
}

Ответ 8

перед именем:

private const string tempDirPath = @"c:\temp\log.log", tempDirNewPath = @"c:\temp\log.new";

        StringBuilder sb = new StringBuilder();
        ...
        File.WriteAllText(tempDirNewPath, sb.ToString());
        File.AppendAllText(tempDirNewPath, File.ReadAllText(tempDirPath));
        File.Delete(tempDirPath);
        File.Move(tempDirNewPath, tempDirPath);
        using (FileStream fs = File.OpenWrite(tempDirPath))
        {   //truncate to a reasonable length
            if (16384 < fs.Length) fs.SetLength(16384);
            fs.Close();
        }

Ответ 9

Следующий алгоритм может решить проблему довольно легко, он наиболее эффективен для любого размера файла, включая очень большие текстовые файлы:

string outPutFile = @"C:\Output.txt";
string result = "Some new string" + DateTime.Now.ToString() + Environment.NewLine;
StringBuilder currentContent = new StringBuilder();
List<string> rawList = File.ReadAllLines(outPutFile).ToList();
foreach (var item in rawList) {
    currentContent.Append(item + Environment.NewLine);
}            
File.WriteAllText(outPutFile, result + currentContent.ToString());  

Ответ 10

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

using System;
using System.IO;
using System.Text;

namespace FilePrepender
{
    public class FilePrepender
    {
        private string file=null;
        public FilePrepender(string filePath)
        {
            file = filePath;
        }
        public void prependline(string line)
        {
            prepend(line + Environment.NewLine);
        }
        private void shiftSection(byte[] chunk,FileStream readStream,FileStream writeStream)
        {
            long initialOffsetRead = readStream.Position;
            long initialOffsetWrite= writeStream.Position;
            int offset = 0;
            int remaining = chunk.Length;
            do//ensure that the entire chunk length gets read and shifted
            {
                int read = readStream.Read(chunk, offset, remaining);
                offset += read;
                remaining -= read;
            } while (remaining > 0);
            writeStream.Write(chunk, 0, chunk.Length);
            writeStream.Seek(initialOffsetWrite, SeekOrigin.Begin);
            readStream.Seek(initialOffsetRead, SeekOrigin.Begin);
        }
        public void prepend(string text)
        {
            byte[] bytes = Encoding.Default.GetBytes(text);
            byte[] chunk = new byte[bytes.Length];
            using (FileStream readStream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using(FileStream writeStream = File.Open(file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
                {
                    readStream.Seek(0, SeekOrigin.End);//seek chunk.Length past the end of the file 
                    writeStream.Seek(chunk.Length, SeekOrigin.End);//which lets the loop run without special cases
                    long size = readStream.Position;
                    //while there a whole chunks worth above the read head, shift the file contents down from the end
                    while(readStream.Position - chunk.Length >= 0)
                    {
                        readStream.Seek(-chunk.Length, SeekOrigin.Current);
                        writeStream.Seek(-chunk.Length, SeekOrigin.Current);
                        shiftSection(chunk, readStream, writeStream);
                    }
                    //clean up the remaining shift for the bytes that don't fit in size%chunk.Length
                    readStream.Seek(0, SeekOrigin.Begin);
                    writeStream.Seek(Math.Min(size, chunk.Length), SeekOrigin.Begin);
                    shiftSection(chunk, readStream, writeStream);
                    //finally, write the text you want to prepend
                    writeStream.Seek(0,SeekOrigin.Begin);
                    writeStream.Write(bytes, 0, bytes.Length);
                }
            }
        }
    }
}

Ответ 11

Поместите содержимое файла в строку. Добавьте новые данные, которые вы хотите добавить в верхнюю часть файла к этой строке - string = newdata + string. Затем переместите позицию поиска файла в 0 и напишите строку в файл.