C#如何在不使用using{}的情况下写入文件

5
我正在编写一个小应用程序,想把操作结果写入文件中。
基本上我想做的是打开一个文件流(我想使用FileStream,但也接受其他建议),将数据写入文件,然后在以后关闭它。
所以我有一个名为ReportFile的类,其中包含以下方法:
.Create( string path )

.WriteInfo( string a, string b, string c ) ; //Or something like this...

//Then sometime in the future

.Close()

因此,使用 ReportFile 类的类将创建一个实例,调用 WriteInfo(..) 多次,直到完成需要执行的任何操作,然后在未来的某个时候调用 Close()
现在我知道我需要在 ReportFile 类上实现 Dispose 模式,以确保如果出现任何问题,文件句柄得到适当处理。
然而,到目前为止,我还没有找到任何关于保持文件打开并检查是否需要关闭的好方法的互联网示例,大多数示例都在 using{} 结构中打开文件进行写入,然后关闭文件。
ReportFile 类中,我想要能够检查 FileStream 实例是否未关闭,以便我可以关闭它并释放资源。
有人知道参考的好链接或其他建议吗?
(哦,我应该提到我不是全职做 C#,这只是一件业余的事情,所以如果这是一个愚蠢的问题,我很抱歉;-))

1
为什么你不想使用 using {} 结构?如果你没有在类外部使用流,这通常是最好的解决方案... - Webleeuw
6个回答

3

您需要一直保持文件打开的特定原因吗?

在这种情况下,我会使用FileMode.Append每次打开文件(或将append=true传递给StreamWriter ctor),然后使用using再次关闭它。例如:

void WriteInfo(string text)
{
    // Second parameter to StreamWriter ctor is append = true
    using(StreamWriter sw = new StreamWriter(logFilePath, true))
    {
         sw.WriteLine(text);
    }
}

采用这种方法,您实际上不需要Create()或Close()方法。如果文件不存在,append=true将创建该文件。

嗨,Ash,感谢回复。是的,我也考虑过这个问题。然而,我正在创建的小应用程序是一个搜索/替换工具,它将记录所有更改并将其保存到文件中以证明它所做的事情。因此,可能会有很多更改需要记录。我担心不断地打开/关闭文件会影响搜索的性能。我不想将它收集的所有数据存储在内存中,因为它可能会产生大量的更改。因此,我考虑打开文件流,将数据刷新,完成后再关闭它。希望这样说得清楚一些;-) - JustAPleb
2
@JustAPleb,我明白你的想法,但开/关不应该成为瓶颈。写入文件会变得更慢,特别是当文件大小增加时。进行一些性能测试,如果你真的发现这是一个问题,将写入缓冲到内存并批量访问文件将提供最大的性能提升。顺便说一句,你不能使用log4net或其他经过验证的日志记录库吗? - Ash
嗨Ash,Log4Net - 我确实考虑过,但以前从未使用过。我会研究一下。感谢你的帮助。 - JustAPleb
1
我可以推荐Log4Net,它在几年前我上次使用时有一些小问题,但它完成了工作。 - Ash

3
< p > ReportFile 只需要一个 TextWriter 实例变量 - 你应该在自己的 Dispose() 方法中释放它。

顺便问一下,为什么你想要一个显式的 Close() 方法?你的调用方应该已经使用了 using 语句,那么为什么他们还想显式地调用 Close 呢?


System.IO 命名空间中的各种流类遵循这种模式(显式实现 IDisposable.Dispose 方法并仅公开 Close 方法)。 - Adam Robinson
1
@Adam:没错,但我认为这更多是历史原因。如果有一个“Close”方法,人们可能会显式地调用它并忘记使用“using”语句 - 在我看来,如果他们必须使用“Dispose”,那么他们更有可能做正确的事情。 - Jon Skeet
1
我同意Jon的观点,如果你通过类实例来维护一个IDisposable资源,那么这个类应该实现IDisposable接口。我只是希望编译器能够更好地支持,在不使用using或其他方式时标记IDisposable实现。你知道有些人不会阅读文档以了解类是否支持IDisposable,或者完全忘记了并相应地处理它。 - ewrankin
@ewrankin:但我们讨论的不是是否要实现IDisposable,而是是否要使用显式实现 IDisposable 并公开一个不同的方法来进行清理。历史上,大多数类型的文件、句柄和流都是“打开”和“关闭”的,因此我认为(在这种特定情况和其他情况下)遵循这种方法是有意义的。 - Adam Robinson
@Adam:注意这里没有“打开”方法,因此惯例已经不存在了。我认为暴露“关闭”可能会鼓励不良习惯,而这本身就是一件坏事,依我看来。 - Jon Skeet
显示剩余2条评论

1

Justa,我认为你可能有点过度思考这个功能。你看到使用构造的示例是因为使用{}进行文件写入非常快速和安全。

很可能你不会每秒钟打开和关闭文件多次,所以没有必要一直保持它处于打开状态,从而冒着在应用程序关闭文件之前未关闭文件的风险(这是一个麻烦的问题)。使用using结构确保资源(在这种情况下是文件)被正确释放和关闭。

编程的另一个建议:不要担心效率问题。首先以最简单的方式使其工作,并仅在必要时提高速度/性能。


你好Psasik,我正在编写的工具是一个搜索和替换应用程序,它将搜索文件夹及其子文件夹中的所有文件,并根据给定的条件进行多次替换。因此,在每个执行搜索的文件之后,它会将所做的更改记录到报告中。如果有很多文件,则可能会频繁地打开/关闭文件。 - JustAPleb

1

public void Create(string path) { mStream = new FileStream(path); }

public void Dispose() { if (mStream != null) mStream.Dispose(); }

公共 void Create(string path) { mStream = 新的 FileStream(path); }

公共 void Dispose() { 如果 (mStream != null) mStream.Dispose(); }


0
我建议使用 "using" 结构,只在保存时保持文件打开状态。
一个想法是在内存中构建内容,然后在准备好时保存它。例如使用 StringBuilder。

0

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