写入 AppData 中的文本文件不起作用 - C#

Writing to a text file in AppData doesn't work - C#

我正在使用以下代码行将用户凭据写入文本文件。它应该在 AppData 中创建目录(它确实如此),但它不会将凭据写入文本文件,而是将其留空!

public void RegisterUserCreds()
{
    string[] creds = { Username.Text, Password.Text };
    string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
    if (!Directory.Exists(roaming + "/Launcher")) 
        Directory.CreateDirectory(roaming + "/Launcher");
    string specificFolder = roaming + "/Launcher/user_info.txt";
    var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    var sw = new StreamWriter(fs);
    sw.WriteLine(Username.Text);
    fs.Close();
}

有什么问题吗?谢谢!

在流上操作时只需使用 using statement:

public static void RegisterUserCreds()
{
    string[] creds = { Username.Text, Password.Text };
    string roaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
    if (!Directory.Exists(roaming + "/Launcher")) Directory.CreateDirectory(roaming + "/Launcher");
    string specificFolder = roaming + "/Launcher/user_info.txt";
    using (var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite))
    {
        using (var sw = new StreamWriter(fs))
        {
            sw.WriteLine(Username.Text);
        }
    }
}

在您的代码中,您在流编写器能够刷新您要写入的更改之前关闭了文件流,因此文件被创建为空。

您关闭了错误的流。当您创建新的流对象并将现有流传递给构造函数时,该新流现在 "owns" 旧流。当您处理较新的流时,它会自动处理旧的。

在您的情况下,您正在关闭 "fs" 流,但 "sw" 流可能还没有实际写入它(它有自己的内部缓冲区)。如果您改为关闭 "sw" 流,它会刷新它的缓冲区(进入 "fs" 流),然后它会为您调用 fs.Dispose() 以确保它完成了同样的事情。

有一个更好的方法,它可以帮助您避免像这样无序地做事,并确保即使抛出异常也能调用 Dispose()(流实现 IDisposable,所以当你完成它们时,你应该总是调用它们的 Dispose() 方法,这样它们就可以在内部 "clean up")。 using 语句非常适合这个,因为它会调用 Dispose() 即使抛出异常(它是用 try/finally 块包装代码的快捷方式):

using (var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    using (var sw = new StreamWriter(fs))
    {
        sw.WriteLine(Username.Text);
    }
}

这与此相同:

try
{
    var fs = File.Open(specificFolder, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    try
    {
        var sw = new StreamWriter(fs);
        sw.WriteLine(Username.Text);
    }
    finally
    {
        sw.Dispose();
    }
}
finally
{
    fs.Dispose();
}

尽管sw.Dispose()会为您调用fs.Dispose(),但再次调用fs.Dispose()也没有坏处。为什么调用 Dispose() 很重要?假设在 sw.WriteLine() 期间抛出异常(例如磁盘不足 space、I/O 错误等)...文件将保持打开状态,直到您的应用程序终止。 using(或 try/catch 版本)无论如何都会确保文件已关闭。

(旁注:对于流,Dispose()Close() 做同样的事情,您不需要同时调用两者。Close() 只需调用 Dispose() - - MS 包含一个名为 Close() 的方法,因为人们习惯于使用文件 API,但 .NET IDisposable 接口使用一个名为 Dispose())[= 的方法30=]

(另一个旁注:从 .NET 4.5 开始,许多流 类 有一个额外的构造函数,它有一个新的 "leaveOpen" 参数......传递 true 会告诉该流不会自动处理原始流)