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

C/C++程序写入文本文件时出现垃圾行的问题排查

问题描述

我有一个程序每2分钟输出一行制表符分隔的数字文本(每行最多51字符),为保留最后100行,先编写了C++版FIFO缓存程序,将其标准输出导入该程序。初始运行正常,但一段时间后文件末尾出现无效垃圾行。随后将该功能整合到原C程序中,采用相同算法,问题依旧。调试发现used变量始终未超过100,且原程序单独输出无异常。运行环境为Angstrom Linux v2018.12(DE10-Standard板),编译未开优化也无改善,请问问题原因是什么?

C++版本代码

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

string lines [100];
int used=0;

ofstream outfile("last100.txt", ios_base::out);

int main()
{
        for (string line; getline(cin, line);)
        {
                if(used<100) //adds new lines to the end of the array while not full
                {
                        lines[used]=line;
                        used++;
                }
                else //if full, then shift lines one position back and add on the end
                {
                        for(int i=0;i<99;i++)
                        {
                                lines[i]=lines[i+1];
                        }
                        lines[99]=line;
                }
                outfile.seekp(0, ios::beg); //seek to the beginning of file
                for(int i=0;i<used;i++) //save the array to the text file and flush
                {
                        outfile.write((lines[i]+'\n').data(),(lines[i]+'\n').size());
                        outfile.flush();
                }
        }
        return 0;
}

C版本关键代码

char lines[100][256];
int used = 0;

int main(int argc, char *argv[])
{
    FILE *outfile = fopen("last100.txt", "w");
    if (outfile == NULL)
    {
        printf("Error opening file for writing.\n");
        return 1;
    }
    
    // other pieces of the program come here
    
    if (used < 100) //again, add to the end if not full
    {
            snprintf (lines[used],256, /* a bunch of integer variables come here */);
            used++;
    }
    else //if full, shift lines one position back and add to the last position
    {
            for (int i = 0; i < 99; i++)
            {
                    strcpy(lines[i], lines[i+1]);
            }
            snprintf (lines[99],256, /* a bunch of integer variables come here */);
    }
    rewind(outfile); //seek to the beginning of the file
    for (int i = 0; i < used; i++) //write to the file and flush
    {
            fprintf(outfile, "%s\n", lines[i]);
            fflush(outfile);
    }
}
问题原因及解决方案

核心原因

问题出在文件写入后未截断多余内容:每次将文件指针移到开头重新写入时,如果本次写入的总字节数小于文件之前的长度,文件末尾未被覆盖的旧数据会保留下来,形成所谓的"垃圾行"。

初始运行正常是因为程序刚启动时,used从0逐渐增加到100,每次写入的总长度都比之前更长,旧内容会被完全覆盖;当used稳定在100后,如果某次写入的总字节数(比如某行内容比之前的短)小于之前文件的长度,就会留下未被覆盖的旧数据,表现为末尾的垃圾行。

修复方案

C++版本修复

在写完所有行后,截断文件到当前写入的位置:

// 在写完所有行的循环之后添加
outfile.seekp(0, ios::end);
outfile.truncate();

优化后的写入部分代码:

outfile.seekp(0, ios::beg); //seek to the beginning of file
for(int i=0;i<used;i++) //save the array to the text file 
{
        outfile.write((lines[i]+'\n').data(),(lines[i]+'\n').size());
}
outfile.seekp(0, ios::end);
outfile.truncate();
outfile.flush();

(注:无需在循环内每次flush,写完所有行后统一flush即可提升效率)

C版本修复

利用ftruncate函数截断文件,需包含<unistd.h>头文件:

// 在写完所有行的循环之后添加
ftruncate(fileno(outfile), ftell(outfile));

优化后的写入部分代码:

rewind(outfile); //seek to the beginning of the file
for (int i = 0; i < used; i++) //write to the file 
{
        fprintf(outfile, "%s\n", lines[i]);
}
ftruncate(fileno(outfile), ftell(outfile));
fflush(outfile);

同样,循环内无需每次flush,统一flush即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 17:10:59