我所拥有的文本文件包含以下数据(分别以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);
}
答案 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...
}