You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何这段C#代码调用SaveRecentLogins时总是抛出IOException?

问题原因分析

你的SaveRecentLogins方法存在明显的文件操作冲突:

  • 先用File.OpenWrite(_fullFilePath)打开了一个文件流,并用using块持有这个流
  • 紧接着又调用await File.WriteAllTextAsync(_fullFilePath, json),而File.WriteAllTextAsync内部会再次尝试打开同一个文件进行写入操作

这两个操作会同时争夺文件的独占访问权,直接导致IOException提示文件被占用。

GetRecentLogins方法的实现是正确的,using块会确保FileStream在异步操作完成后被正确释放,多次调用读取操作本身不会导致文件占用问题。

修复方案

修改SaveRecentLogins方法,二选一即可:

方案一:直接使用File.WriteAllTextAsync(推荐)

去掉多余的File.OpenWrite操作,因为File.WriteAllTextAsync已经封装了完整的打开、写入、关闭流程:

public async Task SaveRecentLogins(IEnumerable<RecentAccount> recentLogins)
{
    string json = JsonSerializer.Serialize(recentLogins, recentLogins.GetType());

    if(json.Length > (1024 * 1024)) // File content would be > 1 MB
    {
        throw new Exception("File would be too large.");
    }
    
    Debug.WriteLine("Calling " + nameof(SaveRecentLogins));

    // 直接调用WriteAllTextAsync,无需手动打开流
    await File.WriteAllTextAsync(_fullFilePath, json);
}

方案二:使用FileStream手动写入

如果需要更精细的流控制,就用FileStream来完成写入,不要调用File.WriteAllTextAsync:

public async Task SaveRecentLogins(IEnumerable<RecentAccount> recentLogins)
{
    string json = JsonSerializer.Serialize(recentLogins, recentLogins.GetType());

    if(json.Length > (1024 * 1024)) // File content would be > 1 MB
    {
        throw new Exception("File would be too large.");
    }
    
    Debug.WriteLine("Calling " + nameof(SaveRecentLogins));

    using (FileStream fileStream = File.OpenWrite(_fullFilePath))
    {
        // 使用JsonSerializer直接序列化到流
        await JsonSerializer.SerializeAsync(fileStream, recentLogins);
        // 确保流的内容写入磁盘
        await fileStream.FlushAsync();
    }
}
额外注意事项
  1. 确保所有调用GetRecentLogins和SaveRecentLogins的地方都使用await,避免异步操作未完成就执行后续代码,导致文件被意外占用
  2. 可以给文件操作加个异步锁,避免多线程同时读写:
    private readonly SemaphoreSlim _fileSemaphore = new SemaphoreSlim(1, 1);
    
    // 在Get方法中使用
    public async Task<IEnumerable<RecentAccount>> GetRecentLogins()
    {
        await _fileSemaphore.WaitAsync();
        try
        {
            // 原有的读取逻辑
        }
        finally
        {
            _fileSemaphore.Release();
        }
    }
    

内容的提问来源于stack exchange,提问作者user2190492

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:07:04