C #: перед началом файла - PullRequest
       29

C #: перед началом файла

33 голосов
/ 27 августа 2009

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

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

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

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

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

Ответы [ 11 ]

28 голосов
/ 29 декабря 2011

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

string currentContent = String.Empty;
if (File.Exists(filePath))
{
    currentContent = File.ReadAllText(filePath);
}
File.WriteAllText(filePath, newContent + currentContent );
12 голосов
/ 27 августа 2009

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

2 голосов
/ 15 мая 2017

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

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's 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);
                }
            }
        }
    }
}
2 голосов
/ 24 марта 2016

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

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());  
2 голосов
/ 27 августа 2009

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

1 голос
/ 27 июля 2012

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

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();
        }
1 голос
/ 30 января 2012

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

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);
                }
            }
        }
    }
}
1 голос
/ 22 октября 2011

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

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

Не очень эффективно, хотя в случае больших файлов.

1 голос
/ 01 мая 2011
// 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);

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

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

1 голос
/ 27 августа 2009

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

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

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

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

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

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