C#:前置到文件的开头

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1343044/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:22:41  来源:igfitidea点击:

C#: Prepending to beginning of a file

c#file-io

提问by Grace

What is the best way to add text to the beginning of a file using C#?

使用 C# 将文本添加到文件开头的最佳方法是什么?

I couldn't find a straightforward way to do this, but came up with a couple work-arounds.

我找不到一个简单的方法来做到这一点,但想出了几个变通办法。

  1. Open up new file, write the text that I wanted to add, append the text from the old file to the end of the new file.

  2. Since the text I want to add should be less than 200 characters, I was thinking that I could add white space characters to the beginning of the file, and then overwrite the white space with the text I wanted to add.

  1. 打开新文件,写下我想添加的文本,将旧文件中的文本附加到新文件的末尾。

  2. 由于我要添加的文本应该少于200个字符,所以我想我可以在文件的开头添加空格字符,然后用我要添加的文本覆盖空格。

Has anyone else come across this problem, and if so, what did you do?

有没有其他人遇到过这个问题,如果有,你是怎么做的?

采纳答案by JP Alioto

Adding to the beginning of a file (prepending as opposed to appending) is generally not a supported operation. Your #1 options is fine. If you can't write a temp file, you can pull the entire file into memory, preprend your data to the byte array and then overwrite it back out (this is only really feasible if your files are small and you don't have to have a bunch in memory at once because prepending the array is not necessarily easy without a copy either).

添加到文件的开头(前置而不是附加)通常不是受支持的操作。您的 #1 选项很好。如果你不能写一个临时文件,你可以把整个文件拉到内存中,将你的数据预先添加到字节数组中,然后将其覆盖掉(这只有在你的文件很小并且你不必这样做的情况下才真正可行)一次在内存中有一堆,因为在没有副本的情况下预先准备数组也不一定容易)。

回答by Ryan Cook

I think the best way is to create a temp file. Add your text then read the contents of the original file adding it to the temp file. Then you can overwrite the original with the temp file.

我认为最好的方法是创建一个临时文件。添加您的文本,然后读取原始文件的内容,将其添加到临时文件中。然后你可以用临时文件覆盖原始文件。

回答by JSB????

You should be able to do this without opening a new file. Use the following File method:

您应该能够在不打开新文件的情况下执行此操作。使用以下 File 方法:

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

Making sure to specify FileAccess.ReadWrite.

确保指定 FileAccess.ReadWrite。

Using the FileStream returned from File.Open, read all of the existing data into memory. Then reset the pointer to the beginning of the file, write your new data, then write the existing data.

使用从 File.Open 返回的 FileStream,将所有现有数据读入内存。然后将指针重置到文件的开头,写入新数据,然后写入现有数据。

(If the file is big and/or you're suspicious of using too much memory, you can do this without having to read the whole file into memory, but implementing that is left as an exercise to the reader.)

(如果文件很大和/或您怀疑使用了太多内存,您可以执行此操作而不必将整个文件读入内存,但将其作为练习留给读者。)

回答by James

Put the file's contents in a string. Append new data you want to add to the top of the file to that string -- string = newdata + string. Then move the seek position of the file to 0 and write the string into the file.

将文件的内容放在一个字符串中。将要添加到文件顶部的新数据附加到该字符串 -- string = newdata + string。然后将文件的seek位置移动到0,并将字符串写入文件。

回答by Chris Moschini

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

Even if what you're writing is small, the Temp file gets the entire original file appended to it before the .Replace(), so it does need to be on disk.

即使您正在编写的内容很小,临时文件也会在 .Replace() 之前将整个原始文件附加到它,因此它确实需要在磁盘上。

Note that this code is not Thread-safe; if more than one thread accesses this code you can lose writes in the file swapping going on here. That said, it's also pretty expensive, so you'd want to gate access to it anyway - pass writes via multiple Providers to a buffer, which periodically empties out via this prepend method on a single Consumer thread.

请注意,此代码不是线程安全的;如果多个线程访问此代码,您可能会丢失此处进行的文件交换中的写入。也就是说,它也非常昂贵,因此无论如何您都希望对其进行门访问 - 通过多个提供者将写入传递到缓冲区,该缓冲区通过单个消费者线程上的此 prepend 方法定期清空。

回答by Bence Horvath

Yeah, basically you can use something like this:

是的,基本上你可以使用这样的东西:

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

Then

然后

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

Not really effective though in case of huge files.

虽然在大文件的情况下并不是很有效。

回答by Victor Martins

This works for me, but for small files. Probably it's not a very good solution otherwise.

这对我有用,但适用于小文件。否则,这可能不是一个很好的解决方案。

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

回答by Ronnie Overby

Use this class:

使用这个类:

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

回答by 3ric

prepend:

前置:

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

回答by Moazzam Shah

The following algorithm may solve the problem pretty easily, it's most efficient for any size of file, including very big text files:

下面的算法可以很容易地解决这个问题,它对于任何大小的文件都是最有效的,包括非常大的文本文件:

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