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

CsvHelper未按预期写入文件问题求助

解决CsvWriter中途终止导致文件为空的问题

这个问题我之前也碰到过!核心原因是StreamWriter和CsvWriter都依赖内存缓冲区——默认情况下,它们不会把每一条写入的数据立刻刷到磁盘,而是攒够一定量(或者等到流关闭时)才一次性写入。所以当你用Ctrl+C或者关闭窗口强制终止程序时,缓冲区里还没来得及写入磁盘的数据就丢了,最后文件自然是空的;而正常结束时,using块会自动调用Dispose()方法,这个方法会先把缓冲区的内容刷到磁盘再关闭流,所以数据能正常保存。

下面给你几个实用的解决方案:

方案1:每次写入后手动刷新缓冲区

在每次写完一条记录后,调用CsvWriter的Flush()方法,强制把缓冲区的数据写入磁盘。这样哪怕中途终止,之前写入的记录已经安全存在文件里了。

修改后的代码:

int i = 0; 
IList<string> pcodes = FindAutobidPcodes(); 
using (StreamWriter sw = new StreamWriter($"HPH_Catalog_{DateTime.Now.Ticks}.csv")) 
using (CsvWriter cw = new CsvWriter(sw, CultureInfo.InvariantCulture)) { 
    cw.Configuration.RegisterClassMap<ProductMap>(); 
    foreach (string code in pcodes) { 
        // 修正了字符串插值里的大括号转义问题
        string search = $"&search=%7b\"catalog\":\"{catalog}\",\"text\":{{\"{code}\":\"{code}\"}}}"; 
        searchQuery.Query = $"{RandomString()}{limit}{page}{search}{gtemplate}&token={token}"; 
        WebPage webPage = QueryProductData(searchQuery.ToString()); 
        cw.WriteRecord(Product.ParseJSON(webPage)); 
        cw.NextRecord(); 
        // 手动刷新缓冲区,确保数据立即写入磁盘
        cw.Flush();
        i++; 
        if(i == 20) { 
            return; 
        } 
    } 
}

方案2:批量刷新,平衡性能和安全性

如果担心每次刷新会轻微影响性能(33k条数据其实完全不用担心,但追求最优的话),可以设置一个批次,比如每100条记录刷新一次,这样既减少IO操作次数,又能避免单次丢失太多数据:

int i = 0; 
IList<string> pcodes = FindAutobidPcodes(); 
using (StreamWriter sw = new StreamWriter($"HPH_Catalog_{DateTime.Now.Ticks}.csv")) 
using (CsvWriter cw = new CsvWriter(sw, CultureInfo.InvariantCulture)) { 
    cw.Configuration.RegisterClassMap<ProductMap>(); 
    foreach (string code in pcodes) { 
        string search = $"&search=%7b\"catalog\":\"{catalog}\",\"text\":{{\"{code}\":\"{code}\"}}}"; 
        searchQuery.Query = $"{RandomString()}{limit}{page}{search}{gtemplate}&token={token}"; 
        WebPage webPage = QueryProductData(searchQuery.ToString()); 
        cw.WriteRecord(Product.ParseJSON(webPage)); 
        cw.NextRecord(); 
        i++; 
        // 每100条记录刷新一次缓冲区
        if (i % 100 == 0) {
            cw.Flush();
        }
        if(i == 20) { 
            return; 
        } 
    } 
    // 循环结束后再刷一次,确保最后一批不足100条的数据也写入磁盘
    cw.Flush();
}

额外优化:监听强制终止信号(控制台应用)

如果你的程序是控制台应用,可以监听Ctrl+C的终止信号,在收到信号时手动执行一次Flush,最大程度减少数据丢失:

// 在程序初始化阶段注册终止信号处理逻辑
CsvWriter cw = null;
Console.CancelKeyPress += (sender, e) => {
    // 确保刷新缓冲区
    cw?.Flush();
    // 延迟终止,保证Flush操作完成
    e.Cancel = true;
    // 完成后退出程序
    Task.Run(() => Environment.Exit(0));
};

// 后续的写入逻辑
int i = 0; 
IList<string> pcodes = FindAutobidPcodes(); 
using (StreamWriter sw = new StreamWriter($"HPH_Catalog_{DateTime.Now.Ticks}.csv")) {
    cw = new CsvWriter(sw, CultureInfo.InvariantCulture);
    cw.Configuration.RegisterClassMap<ProductMap>(); 
    foreach (string code in pcodes) { 
        string search = $"&search=%7b\"catalog\":\"{catalog}\",\"text\":{{\"{code}\":\"{code}\"}}}"; 
        searchQuery.Query = $"{RandomString()}{limit}{page}{search}{gtemplate}&token={token}"; 
        WebPage webPage = QueryProductData(searchQuery.ToString()); 
        cw.WriteRecord(Product.ParseJSON(webPage)); 
        cw.NextRecord(); 
        i++; 
        if(i == 20) { 
            return; 
        } 
    } 
}

核心思路就是:不要只依赖using块的自动清理来处理异常或强制终止场景,主动控制缓冲区的刷新时机,确保数据及时落地到磁盘。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 14:18:11