我有一个名为“input.txt”的文件,其中包含一些值。我正在编写将在该文件中找到最小值的程序,并将该最小值替换为作为命令行参数给出的数字 - 如果该命令行参数大于最小值。这些值代表室温,因此可以使用事实来找到最小值。此外,需要锁定文件的那部分(新数字替换最小值)。
例子:
$ ./prog 23
文件:21 25 19 22 24
文件:21 25 23 22 24
$ ./prog 29
文件:21 25 23 22 24
文件:29 25 23 22 24
代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdint.h>
/* Function that handles errors */
void fatal_error(const char *message){
perror(message);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv){
if(argc != 2)
fatal_error("Bad arguments.\n");
/* Fetching command line argument */
int temp = atoi(argv[1]);
/* Opening file and checking for errors */
FILE *file = fopen("input.txt", "r+");
if(!file)
fatal_error("Unable to open file.\n");
/* Finding minimum in the file */
int min = 200;
int value;
while(fscanf(file, "%d", &value) != EOF)
if(value < min)
min = value;
/* Exiting if nothing needs to change */
if(temp <= min)
return 0;
/* Creating file descriptor from stream and checking for errors */
int fdOpen = fileno(file);
if(fdOpen == -1)
fatal_error("Unable to open file descriptor.\n");
/* Moving offset to the beginning of the file */
off_t of = lseek(fdOpen,0,SEEK_SET);
printf("Ofset pre petlje: %jd\n", (intmax_t)of);
while(1){
/* I'm reading file all over again */
if(fscanf(file, "%d", &value) == EOF)
fatal_error("Reached end of file.\n");
/* If I reached minimum */
if(value == min){
/* I lock that part of the file - temperatures are two digit numbers*/
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_CUR;
lock.l_start = -2;
lock.l_len = 2;
/* I create lock */
if(fcntl(fdOpen,F_SETLK, &lock) == -1){
if(errno == EACCES || errno == EAGAIN)
fatal_error("File is locked.\n");
}
/* Moving two positions back from current position */
off_t offset;
if((offset = lseek(fdOpen, -2, SEEK_CUR)) == -1)
fatal_error("lseek error.\n");
/* Inserting read command line value into file */
fprintf(file, "%d", temp);
/* Unlocking */
lock.l_type = F_UNLCK;
if(fcntl(fdOpen, F_SETLK, &lock) == -1)
fatal_error("Unable to destroy lock.\n");
/* Closing file descriptor, and breaking loop */
close(fdOpen);
break;
}
}
return 0;
}
然而这不起作用。文件不会改变。问题是 - 我知道这是正确的方法。我编写了基本相同的程序,例如将单词"aa"的每次出现都更改为"bb"。它基本上是相同的概念。
我试过了:
- 我试过
fscanf()
在while()
循环之前和之后获取偏移量。在第一个fscanf
偏移量设置为 0 之前 - 文件的开头。在第一个fscanf
偏移量设置为文件末尾之后,每次迭代后偏移量都保留在文件末尾。 - 我试过
ftell()
在这些相同的地方使用printf()
并ftell()
给我正确的偏移量。然而,ftell()
在 while 循环中仍然给出了文件的结尾。我也尝试过使用fseek()
而不是lseek()
(即使我知道在其实现中fseek()
使用lseek()
)。还是一样的结果。 - 我试过使用
char*
缓冲区而不是值。基本上要使用fscanf(file,"%s",buffer)
,转换该值以检查读取值是否最小,然后我习惯于fprintf(file,"%s",buffer)
编写它。然而同样的结果。 - 我试过锁定整个文件(我想 - 也许有问题),但是,同样的结果。
代码:
这是我提到的第二个使用相同概念的程序。此代码有效,但我也尝试在这里打印偏移量,并且偏移量也在文件末尾。
int main(int argc, char **argv){
if(argc != 4)
fatal_error("You must enter exactly 4 arguments.\n");
FILE *f = fopen(argv[1], "r+");
if(!f)
fatal_error("Unable to open file for reading and writing.\n");
int fd = fileno(f);
if(fd == -1)
fatal_error("Unable to fetch file descriptor for file.\n");
char word[MAX_LEN + 1];
int word_len = strlen(argv[2]);
while(fscanf(f,"%s",word) != EOF){
printf("%jd\n", lseek(fd,0,SEEK_CUR));
if(!strcmp(argv[2],word)){
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_CUR;
lock.l_start = -word_len;
lock.l_len = word_len;
if(fcntl(fd, F_SETLKW, &lock) == -1)
fatal_error("File locking failed.\n");
if(lseek(fd, -word_len, SEEK_CUR) == -1)
fatal_error("Lseek error.\n");
fprintf(f, "%s", argv[3]);
lock.l_type = F_UNLCK;
if(fcntl(fd, F_SETLK, &lock) == -1)
fatal_error("Failed to release lock.\n");
}
}
}
如您所见,这是完全相同的概念。第二个程序有效,第一个无效。
我现在很困惑。如果我从文件流创建文件描述符,然后lseek()
在该文件描述符上使用来更改偏移量,流的偏移量也会改变吗?如果您使用fscanf()
从流中读取某些内容,是否offset_t
会像从文件中读取一样多地进行更改?如果我fscanf()
与格式说明符%d
和一起使用,更改偏移量有什么区别%s
吗?