我拥有的文本文件包含以下数据(分别以 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 至 17 在文本文件中。我真的不知道该怎么做,因为我是 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);
}
最佳答案
好的,看起来你这样做是正确的。一些评论:
重复性和可读性
你经常重复自己;变化
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
每个 token 末尾的字符,当您尝试将其写回文件时会很痛苦。还有一点要注意;因为您不知道新号码可能有多少位数,所以您可能需要调整缓冲区的大小以进行补偿。函数签名假定这已完成,并返回一个数字,表示添加或删除了多少字符(如果有)。我的一般方法是遍历每个字符以寻找换行符。每次找到一个,检查它是否是正确的行,如果是,获取值,确定是否需要调整缓冲区大小并在必要时这样做。完成后,更改值。
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
时才会调用评估为真。这称为 short circuit evaluation .显然,上面的代码调用了几个尚未创建的函数,因此您的部分任务将是实现它们。请注意,第二个参数已通过
fl_size
定义为 size_t
不是 long
即使 fl_size
是长。您应该将此变量更改为 size_t
.下面我提供了函数签名。由于您正在尝试学习 C,因此我不会为您实现它们。
每次遇到换行符时都会调用此函数,并将“索引”设置为该换行符的位置。如果在这个位置没有找到标识符,它应该返回一个 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 = 2int 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...
}
关于c - 我在带有分隔符的文本文件中有一组值如何使用 C 编程修改值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39815855/