我在带有分隔符的文本文件中有一组值,如何使用C编程修改值

时间:2016-10-02 10:03:26

标签: c arrays text-files

我所拥有的文本文件包含以下数据(分别以K和D和P作为ID开头)

K1234:Green_Book:A_green_book:10:
K3346:Red_Book:A_red_book:7:
D3333:Grey_Book:A_grey_book:15:
D1111:Black_Book:A_black_book:1:
P0000:White_Book:A_white_book:6:

我想要做的是修改以D3333开头的行中的数据,并将文本文件中的值从 15更改为。我真的不知道该怎么做,因为我是C编程新手,这一直困扰着我好几天。我已经在网上搜索,但我的搜索无济于事。如果有人可以帮助我使用可以做到这一点或类似的代码,我会非常感激。感谢。

这是我到目前为止所做的:

void show(){
    FILE * fl;
    long fl_size;
    char * buffer;
    size_t res;

    fl = fopen("inventItems.txt", "r+");
    if (fl == NULL) {
        fprintf(stderr, "File error\n");
        _getch();
        exit(1);
    }

    fseek(fl, 0, SEEK_END);
    fl_size = ftell(fl);
    rewind(fl);

    buffer = (char*)malloc(sizeof(char)*fl_size);
    if (buffer == NULL) {
        fputs("Memory error", stderr);
        _getch();
        exit(2);
    }

    res = fread(buffer, 1, fl_size, fl);
    if (res != fl_size) {
        fputs("Reading error", stderr);
        _getch();
        exit(3);
    }
    char * strtok_res;
    strtok_res = strtok(buffer, ":");
    while (strtok_res != NULL)
    {
        printf("%s\n", strtok_res);//this prints the values from the file to a new line when i test it
        //however i DO NOT KNOW how to modify and save it back onto the text file
        strtok_res = strtok(NULL, ":");
        _getch();
    }
    _getch();
    fclose(fl);
    free(buffer);

}

1 个答案:

答案 0 :(得分:2)

好的,看起来你正沿着正确的方向做这件事。几条评论:

复制和可读性

你正在重复自己;

的变化
if(whateverPointer == NULL) {
   fprintf("My error message", stderr);
   _getch();
   exit(2);
}

在三个不同的场合使用;所以应该移到一个单独的函数中,该函数将char*(字符串)消息传递给fprintf(),这样你就可以了

if(whateverPointer == NULL) {
   errorThenDeath("My message", 2);
}

这可能看起来与此问题无关,但除了成为一个良好的习惯,它将使您的代码更容易阅读。您的代码越容易阅读,当您遇到困难时,其他人就越容易帮助您:永远记住这个

在类似的情况下,您已指出要使用特定标识符来更改特定行。考虑到这一点,您应该解决您的问题以识别此特定问题,因此执行该特定任务的代码应包含在可能具有此类签名的函数中。

int changeLineValue(char** buffer, size_t size, char* identifier, int newValue) 
{
...
}

请注意双指针(char**)这是指向原始char*的指针。在此函数内部时,您可以通过取消引用(*)来获取原始指针

*buffer = "hello";

将缓冲区更改为字符串'hello'。

问题

我不确定将缓冲区标记为正确的方法。 strtok实际上在每个令牌的末尾写入\0个字符,这会让您在尝试将其写回文件时感到痛苦。另外需要注意的事项;因为您不知道新数字可能有多少位数,您可能需要调整缓冲区大小以进行补偿。函数签名假设已完成此操作,并返回一个数字,表示添加或删除了多少字符(如果有)。

我的一般方法是遍历每个角色寻找换行符。每次找到一个,检查它是否是正确的行,如果是,获取值,确定是否需要调整缓冲区的大小,并在必要时执行此操作。完成后,更改值。

int changeLineValue(char** buffer, size_t size, char* identifier, int newValue) 
    for(int i = 0; i < size; i++) {
        if(buffer[i] == '\n' && isCorrectLine(*buffer, size, i)) {
           int oldVal = getCurrentValue(*buffer, size, i);
           int resize = getDigitsDifference(oldVal, value);
           if(resize != 0) {
              resizeBuffer(buffer, resize);
           }
           modifyValueInPosition(buffer, fl_size, i, value);
           return resize;
        }
    }
}

请注意;由于C语言的工作方式,isCorrectLine(...)仅在buffer[i] == \n求值为true时才会被调用。这称为short circuit evaluation

显然,上面的代码调用了一些尚未创建的函数,因此您的部分任务将是实现它们。请注意,已传递fl_size的第二个参数定义为size_t而不是long,即使fl_size很长。您应该将此变量更改为size_t

下面我提供了功能签名。由于您正在尝试学习C,我不打算为您实现它们。

每次遇到newwline时都会调用此函数,并将'index'设置为该换行符的位置。如果在此位置未找到标识符,则应返回0;如果已在此位置找到标识符,则应返回1。此时不要更改缓冲区中的任何内容

int isCorrectLine(char* buffer, char* identifier, size_t size, int index) {
}

此函数应沿着该行迭代并在下一个换行符('\ n')之前返回该数字

int getCurrentValue(char* buffer, size_t fl_size, i) {
}

此数字应返回每个数字所包含的数字之间的差异。例如。 1 = 1位,324 = 3位数,因此3 - 1 = 2

int digitsDifference(int old, int new) {
}

此函数采用双指针char**)并使用更大或更小的缓冲区重新分配内存,以便在需要时考虑不同的位数。

void resizeBuffer(char** buffer, int resize) {
    *buffer = // This is how you change the original pointer. Line is still incomplete 
}

现在缓冲区的大小正确,您可以继续更改缓冲区中的值。同样,此函数在正确行之前的换行符位置传递,因此您需要沿着行迭代,更改位置值。如果您发现自己覆盖换行符(因为新号码较长),您可能需要在此值之后移动所有字符

int modifyValueInPosition(char* buffer, size_t fl_size, int index) {
}

写入文件

更改原始缓冲区后,将其写回文件非常简单。你的主要功能现在应该是这样的

int main() {
    // ...code that gets buffer from file. Note, make sure you close the file handle
    // afterwards it isn't good practise to leave a file handle open

    fl_size += changeLineValue(buffer, fl_size, identifier, newValue);

    // ...Reopen file handle as you did before ...

    fwrite(buffer, sizeof(char), fl_size, fileHandle);

    // ...Close file handle...
}