C语言 文件写入特定行 下一行内容消失了部分?

新手上路,请多包涵

题目描述

输入1进入log功能界面
log功能界面
1:文件log保存功能
2:文件log打印功能
0:返回上一级菜单


输入 1 进入 文件log保存功能
文件log保存功能描述:读取1个数字 假如是3
将"[index]get_num = 3\r\n"这句话打印到文件中 从文件后面追加
如第一次保存log 创建文件log.txt
文件里面的内容为:
1 get_num=3
第二次调用保存log功能 假如输入值为1
文件里面的内容应该为
1 get_num=3
2 get_num=1
假如第三到第十次的输入值均为2
文件里面的内容为:
1 get_num=3
2 get_num=1
3 get_num=2
4 get_num=2
5 get_num=2
6 get_num=2
7 get_num=2
8 get_num=2
9 get_num=2
10 get_num=2
要求一:文件最多保存的log数量为10条 当有第11条log的时候 应该覆盖第1条log
假如第11次输入值为4 文件里面的内容为:
11 get_num=4
2 get_num=1
3 get_num=2
4 get_num=2
5 get_num=2
6 get_num=2
7 get_num=2
8 get_num=2
9 get_num=2
10 get_num=2
要求二:再次进入文件log保存功能时 当文件存在的时候应该也往后追加
如上一次退出log保存功能时 文件内容为:
11 get_num=3
2 get_num=1
3 get_num=2
4 get_num=2
5 get_num=2
6 get_num=2
7 get_num=2
8 get_num=2
9 get_num=2
10 get_num=2
再次进入文件log保存功能 输入值为5 此时文件的内容为:
11 get_num=3
12 get_num=1
3 get_num=2
4 get_num=2
5 get_num=2
6 get_num=2
7 get_num=2
8 get_num=2
9 get_num=2
10 get_num=2

自己的思路

我使用了一个队列,里面记录了index 和 后面的num,打算是当index超过11是,用fgets和sscanf函数去获取对应文本内index确定写入行号,然后用fseek函数偏移文件指针去写入数据

相关代码

主要功能写在log_save函数

/*
 * @Descripttion   : log function
 * @Author         : Ethan.liang
 * @Date           : 2022-07-18 09:20:36
 * @LastEditors    : Do not Edit
 * @LastEditTime   : 2022-07-24 10:05:34
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

typedef int dataType;

dataType log_ret = -1;
dataType log_num = -1;
dataType log_cnt = 1;
dataType log_index = 0;
dataType log_sel = -1;
dataType line_len = 0;
dataType len = 0;

char str_temp[512] = {0};
char linebuffer[512] = {0};
char log_buffer[512] = {0};

#define QUEUEMAX 10

typedef struct QueueNode
{
    dataType _data; //用来存储数据
    dataType _index;
    struct QueueNode *_next; //用来指向下一个结构体
} QueueNode, *P_Node;

typedef struct Queue
{
    QueueNode *_head; //存放整个队列的队头
    QueueNode *_tail; //存放整个队列的队尾
} Queue, *P_Queue;

int log_window();
int log_save(P_Queue log_que);
int log_print();

//初始化
P_Queue QueueInit(P_Queue log_que);

//销毁
P_Queue QueueDestory(P_Queue log_que);

//入队
P_Queue QueuePush(P_Queue log_que, dataType log_num);

//出队
P_Queue QueuePop(P_Queue log_que);

//访问队首的元素
dataType QueueFront(Queue *log_que);

//访问对尾的元素
dataType QueueBack(Queue *log_que);

//返回1是空,返回0是非空
int QueueEmpty(Queue *log_que);

//获取数据的个数
int QueueSize(Queue *log_que);

//初始化
P_Queue QueueInit(P_Queue log_que)
{
    assert(log_que);                        //判断指针的有效性
                                            // log_que->_head->_index = 1;
    log_que->_head = log_que->_tail = NULL; //队头和队尾指向空指针

    return log_que;
}
//销毁
P_Queue QueueDestory(P_Queue log_que)
{
    assert(log_que);
    QueueNode *cur = log_que->_head;
    while (cur)
    {
        QueueNode *next = cur->_next;
        free(cur);
        cur = next;
    }
    log_que->_head = log_que->_tail = NULL;

    return log_que;
}

//入队
P_Queue QueuePush(P_Queue log_que, dataType log_num)
{
    assert(log_que);
    P_Node newnode = (P_Node)malloc(sizeof(P_Node)); //为新节点申请内存空间
    if (newnode == NULL)                             //判断内存空间是否申请成功
    {
        printf("内存不足!\n");
        exit(-1);
    }
    newnode->_data = log_num;   //新节点储存数据
    newnode->_next = NULL;      //新节点的下一个指向NULL,即新节点作为队尾
    if (log_que->_head == NULL) //将新节点入队
    {
        log_que->_head = log_que->_tail = newnode;
    }
    else
    {
        log_que->_tail->_next = newnode;
        log_que->_tail = newnode;
    }

    return log_que;
}
//出队
P_Queue QueuePop(P_Queue log_que)
{
    assert(log_que);
    assert(log_que->_head);

    if (log_que->_head == NULL)
    {
        // printf("%d\n",__LINE__);
        free(log_que->_head);
        log_que->_head = log_que->_tail = NULL;
    }
    else
    {
        QueueNode *next = log_que->_head->_next;
        // printf("%d\n",__LINE__);

        free(log_que->_head);
        // printf("%d\n",__LINE__);
        log_que->_head = next;
    }
    // printf("%d\n",__LINE__);

    return log_que;
}

//访问队首的元素
dataType QueueFront(Queue *log_que)
{
    assert(log_que);
    assert(log_que->_head);
    return log_que->_head->_data;
}

//访问队尾的元素
dataType QueueBack(Queue *log_que)
{
    assert(log_que);
    assert(log_que->_tail);
    return log_que->_tail->_data;
}

//返回1是空,返回0是非空
int QueueEmpty(Queue *log_que)
{
    assert(log_que);
    return log_que->_head == NULL ? 1 : 0;
}

// 获取数据的个数
int QueueSize(Queue *log_que)
{
    assert(log_que);
    QueueNode *cur = log_que->_head;
    int size = 0;
    while (cur)
    {
        ++size;
        cur = cur->_next;
    }
    return size;
}

dataType log_save(P_Queue log_que)
{
    char log_info[64];

    printf("请输入要保存的数:\n");
    log_ret = scanf("%d", &log_num);
    if (log_ret)
    {
        getchar();
    }
    else
    {
        printf("请输入数字!\n");

        return 0;
    }

    FILE *fp;

    log_index++;
    if (log_cnt <= QUEUEMAX)
    {
        fp = fopen("./log.txt", "a+");
        if (NULL == fp)
        {
            perror("open log.txt error>>>");
            exit(1);
        }

        QueuePush(log_que, log_num);
        // printf("%d\n",__LINE__);
        // getchar();

        log_que->_tail->_index = log_index;
        log_que->_tail->_data = log_num;

        // snprintf(log_info, sizeof(log_info), "[ %d ]get_num=%d\n", log_que->_tail->_index, log_que->_tail->_data);
        // fwrite(log_info, strlen(log_info), 1, fp);
        // snprintf(str_temp, sizeof(str_temp), "%d get_num= %d\n", log_que->_tail->_index, log_que->_tail->_data);
        // fputs(str_temp, fp);
        fprintf(fp, "%d get_num= %d \n", log_que->_tail->_index, log_que->_tail->_data);

        printf("QueueBack:%d, num:%d\n ", log_que->_tail->_index, QueueBack(log_que));
        printf("QueueFront:%d, num:%d\n", log_que->_head->_index, QueueFront(log_que));

        log_cnt++;

        fclose(fp);
    }
    else
    {
        // rewind(fp);
        // log_cnt = 0;
        fp = fopen("./log.txt", "r+");
        if (NULL == fp)
        {
            perror("open log.txt error>>>");
            exit(1);
        }

        QueuePush(log_que, log_num);
        // printf("%d\n",__LINE__);
        // getchar();

        log_que->_tail->_index = log_index;
        log_que->_tail->_data = log_num;

        while (fgets(linebuffer, 513, fp))
        {
            log_ret = ftell(fp);
            printf("log_ret:%d\n", log_ret);
            printf("linebuffer:%s", linebuffer);
            line_len = strlen(linebuffer);
            printf("line_len:%d\n", line_len);
            len += line_len;
            printf("len:%d\n", len);

            dataType index_tmp, num_tmp;

            sscanf(linebuffer, "%d%s%d", &index_tmp, str_temp, &num_tmp);
            
            index_tmp = index_tmp % 10;
            printf("index_tmp:%d\n", index_tmp);
            int que_idx_tmp = (log_que->_tail->_index) % 10;
            printf("que_idx_tmp:%d\n", que_idx_tmp);
            printf("que_idx_tmp:%d\n", que_idx_tmp);
            sleep(1);

            if ( index_tmp == que_idx_tmp )
            {
                len -= strlen(linebuffer);
                printf("len:%d\n", len);
                log_ret = fseek(fp, len , SEEK_SET);
                if(log_ret < 0)
                {
                    perror("fseek");
                    return -1;
                }
                
                fprintf(fp, "%dget_num= %d \n", log_que->_tail->_index, log_que->_tail->_data);
                // snprintf(str_temp, sizeof(str_temp), "%d get_num= %d\n", log_que->_tail->_index, log_que->_tail->_data);
                // fputs(str_temp, fp);
                log_ret = fseek(fp, 0, SEEK_SET);
                if(log_ret < 0)
                {
                    perror("fseek");
                    return -1;
                }
                // fprintf(fp, " ");
                // flen = ftell(fp);
                // printf("flen:%d\n", flen);
                // fseek(fp, -(flen - line_len), SEEK_CUR);

                QueuePop(log_que);
                printf("QueueBack:%d, num:%d\n ", log_que->_tail->_index, QueueBack(log_que));
                printf("QueueFront:%d, num:%d\n", log_que->_head->_index, QueueFront(log_que));

                
                break;

            }
        }


        fclose(fp);
        log_cnt++;
        // log_cnt = 0;
    }
}

int log_window()
{
    // system("clear");
    printf("|***********log功能界面************|\n");
    printf("|       1:文件保存log功能          |\n");
    printf("|       2:文件log打印功能          |\n");
    printf("|       0:返回上一级菜单           |\n");
    printf("|**********************************|\n");
}

int main(int argc, char const *argv[])
{
    // index = 1;
    // P_Node head = new_node(0, 0);
    P_Queue log_que;
    QueueInit(log_que);

    dataType log_sel = -1;

    while (1)
    {
        log_window();

        log_ret = scanf("%d", &log_sel);
        if (-1 == log_ret)
        {
            printf("请重新输入!\n");
            return log_ret;
        }
        else
        {
            getchar();
        }
        printf("puts:%d\n", log_sel);

        switch (log_sel)
        {
        case 1:
            log_save(log_que);
            break;

        case 2:
            // log_print();
            break;

        default:

            return 0;
        }
    }

    free(log_que);
    return 0;
}

你期待的结果是什么?实际看到的错误信息又是什么?

现在问我输入地是一个数据时,能成功写入,但文件的下一行会莫名消失几个字符
image.png
如果我在第一行输入字符比第十一行多的话情况又不同:
比如我在第一行输入111111
image.png
十一行写入1
image.png
想知道为什么会这样,解决的方法又是怎样的

阅读 2.2k
1 个回答

如果某位置有数据,直接在该位置写入新数据的话,会覆盖(替换)旧数据

原来的内容是这样

1 get_num= 1 \n2 get_num= 1 \n

image.png

写入第 11 个后就变成

11 get_num= 1 \n get_num= 1 \n

image.png

同理,原来的内容是这样

1 get_num= 111111 \n2 get_num= 1 \n

image.png

写入第 11 个后就变成

11 get_num= 1 \n11 \n2 get_num= 1 \n

image.png

因此正确的做法是,先读取后面的数据,然后写入新数据,再重新写入后面的数据,注意文件总大小要调整

image.png

image.png

当然,不用 r+ 模式,用 w 模式也是可以的,把数据存到循环队列里(用数组即可,不必用链表),每次把队列写入一遍即可

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进