С#: предварительная подготовка к началу файла
Каков наилучший способ добавить текст в начало файла с помощью С#?
Я не мог найти простой способ сделать это, но придумал пару обходов.
-
Откройте новый файл, напишите текст, который я хотел добавить, добавьте текст из старого файла в конец нового файла.
-
Поскольку текст, который я хочу добавить, должен быть меньше 200 символов, я думал, что могу добавить символы пробела в начало файла, а затем переписать пробел с текстом, который я хотел добавить.
Кто-нибудь еще сталкивается с этой проблемой, и если да, что вы сделали?
Ответы
Ответ 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 и напишите строку в файл.