C#使用从FileStream创建的StreamWriter重写文件

本文关键字:StreamWriter 重写 文件 创建 FileStream | 更新日期: 2023-09-27 18:21:32

我需要操作文件的内容:

 FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);               
 StreamReader sr = new StreamReader(fs);
 StreamWriter sw = new StreamWriter(fs);
 newString = someStringTransformation(sr.ReadToEnd());
 sw.Write(newString);
 fs.flush();
 fs.Close();

但是,上面添加了newString,而不是用新的更改覆盖文件。需要这样做,以便在读取和写入之间没有其他应用程序可以访问该文件,这就是为什么我要从FileStream对象创建读取器和写入器。

我知道您可以创建一个StreanWriter,其中第二个参数设置为false,如下所述。但是,当如上所述创建StreamWriter时,这似乎不是参数之一。

C#使用从FileStream创建的StreamWriter重写文件

您遇到的问题是从流中读取会前进到文件的末尾。然后将追加进一步的写入。

这将实现完全覆盖。

using(FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
{
    StreamReader sr = new StreamReader(fs);
    using (StreamWriter sw = new StreamWriter(fs))
    {
        newString = someStringTransformation(sr.ReadToEnd());
        // discard the contents of the file by setting the length to 0
        fs.SetLength(0); 
        // write the new content
        sw.Write(newString);
    }
}

为什么要使用SetLength?您的新内容可能比现有字符串短!您最不希望看到的是文件末尾的旧内容。

这里需要采取几个步骤,但让我明确我的假设:

您需要在整个操作过程中保持文件打开和锁定,以防止其他人在此期间访问该文件。

话虽如此,以下是您需要做的:

  1. 您需要使用StreamReader读取内容,正如您所做的那样
  2. 您需要将基础流重新定位到起点,其位置已通过读取器进行读取而更改
  3. 您需要通过StreamWriter写出转换后的内容,正如您所做的那样
  4. 由于下一步的原因,您需要刷新写入程序
  5. 您需要将基础流/文件截断到其当前位置,以处理缩短内容的转换

所有这些的代码可能看起来像这个LINQPad程序:

void Main()
{
    const string filePath = @"d:'temp'test.txt";
    var encoding = Encoding.UTF8;
    using (var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
    using (var reader = new StreamReader(stream, encoding))
    using (var writer = new StreamWriter(stream, encoding))
    {
        // Read
        var contents = reader.ReadToEnd();
        // Transform
        var transformedContents = contents.Substring(0, Math.Max(0, contents.Length - 1));
        // Write out transformed contents from the start of the file
        stream.Position = 0;
        writer.Write(transformedContents);
        writer.Flush();
        // Truncate
        stream.SetLength(stream.Position);
    }
}

只需使用:

FileStream fs = System.IO.File.Create(filePath);

File.Create将创建或覆盖一个文件并返回文件流。

您可以使用Linq:来避免这些低级别的Stream及其Reader/Writer

  File.WriteAllText(filePath, someStringTransformation(File.ReadAllText(filePath)));

也许这会有所帮助。

只需使用FileMode.OpenFileMode.Truncate来覆盖文件:

namespace System.IO
{
    //
    // Summary:
    //     Specifies how the operating system should open a file.
    [ComVisible(true)]
    public enum FileMode
    {
        ...
        //
        // Summary:
        //     Specifies that the operating system should create a new file. If the file already
        //     exists, it will be overwritten. This requires System.Security.Permissions.FileIOPermissionAccess.Write
        //     permission. FileMode.Create is equivalent to requesting that if the file does
        //     not exist, use System.IO.FileMode.CreateNew; otherwise, use System.IO.FileMode.Truncate.
        //     If the file already exists but is a hidden file, an System.UnauthorizedAccessException
        //     exception is thrown.
        Create = 2,
        //
        ...
    }

namespace System.IO
{
    //
    // Summary:
    //     Specifies how the operating system should open a file.
    [ComVisible(true)]
    public enum FileMode
    {
        ...
        //
        // Summary:
        //     Specifies that the operating system should open an existing file. When the file
        //     is opened, it should be truncated so that its size is zero bytes. This requires
        //     System.Security.Permissions.FileIOPermissionAccess.Write permission. Attempts
        //     to read from a file opened with FileMode.Truncate cause an System.ArgumentException
        //     exception.
        Truncate = 5,
        ...
    }

您可以做的是重新定位流,并删除缓冲的数据,以确保没有任何阻碍。举个例子:

FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);               
 StreamReader sr = new StreamReader(fs);
 StreamWriter sw = new StreamWriter(fs);
 newString = someStringTransformation(sr.ReadToEnd());
    sr.Position = 0;
    sr.DiscardBufferedData(); 
    sw.Position = 0;
 sw.Write(newString);
 fs.flush();
 fs.Close();

如果新数据小于旧数据,则需要截断剩余数据。用CCD_ 9。