C# - 文件流:同时锁定文件,读取不截断,写入截断

7

我想我的标题不够清晰。

我来解释一下:

我可以使用FileStream写入和读取文件。

FileStream fs = new FileStream("C:\\Users\\Public\\text.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);

private void button1_Click(object sender, EventArgs e)
{
    fs.Seek(0,0);
    StreamReader sr = new StreamReader(fs);
    textbox.Text = sr.ReadToEnd();
}

private void button2_Click(object sender, EventArgs e)
{
    StreamWriter sw = new StreamWriter(fs);
    sw.Write(textbox.Text);
    sw.Flush();
}

这样其他程序就不能使用该文件,但我也无法删除内容。对其进行写入只会添加字符串,而不是替换内容。

或者我可以不使用FileStream:

private void button1_Click(object sender, EventArgs e)
{
    StreamReader sr = new StreamReader("C:\\Users\\Public\\text.txt");
    textBox1.Text = sr.ReadToEnd();
    sr.Close();
}

private void button2_Click(object sender, EventArgs e)
{
    StreamWriter sw = new StreamWriter("C:\\Users\\Public\\text.txt", false);
    sw.Write(textBox1.Text);
    sw.Close();
}

这种方式可以替换文件内容,但对文件没有锁定。

但我希望同时实现两者。有什么解决方案吗?


使用FileStream.SetLength()截断文件。 - Hans Passant
3个回答

15

在您的第一个示例中,您需要在写入之前重置流以替换文件内容,而不是将其附加到文件末尾:

private void button2_Click(object sender, EventArgs e)
{
    fs.Seek(0,0);
    fs.SetLength(Encoding.UTF8.GetBytes(textbox.Text).Length));
    StreamWriter sw = new StreamWriter(fs);
    sw.Write(textbox.Text);
    sw.Flush();
}

1
不,我认为这不是一个好的做法。你所建议的,在我测试的范围内,就像文本编辑器中的“插入”模式一样有效。如果我的先前文本很长,那么只有前面的字符会被覆盖。例如,文件包含“OOOOOOOOOO”,我在程序中写入“IIIII”到该文件,则该文件将包含“IIIIOOOOO”。 - pikachu
1
@pikachu - 你需要在 FileStream 上使用 SetLength 来截断它。回答已更新,假设使用 UTF8 - Oded

1
如果将流截断为0,它也可以工作,并且无需计算新文件大小(以字节为单位)。
fs.Seek(0,0);
fs.SetLength(0);

0

如果您想覆盖文件内容,需要执行两个操作:

  1. 将EndOfFile设置为0,
  2. 将文件大小设置为0。

如果您使用FileStream FileMode.Truncate,则只需调用一个系统函数即可将分配大小和eof设置为0。 从procMon(SysInteranls)中查看: operationSeqence_Truncate

如果您使用FileStream FileMode.OpenOrCreate(或Open)并使用fs.Seek(0,0)+ fs.SetLength(0)或仅使用fs.SetLength(0),则通过调用两个系统函数来完成相同的操作。 从procMon(SysInteranls)中查看: operationSeqence-SetLengthWithSeekOrOnlySetLength

我更喜欢使用第一种方式。代码清晰,没有额外的函数调用。我们只设置模式,不做其他事情。

using (var fileStream = new FileStream(path, FileMode.Truncate, FileAccess.Write, FileShare.Read))
using (var binaryWriter = new BinaryWriter(fileStream, Encoding.Unicode))
{
  binaryWriter.Write(bytes, 0, bytes.Length);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接