【问题标题】:reset the file location using lseek() system call使用 lseek() 系统调用重置文件位置
【发布时间】:2019-09-02 22:34:28
【问题描述】:

我尝试使用系统调用 lseek() 来取回文件的开头或到达文件的结尾。

我使用的确切代码是:

int location = lseek(fd, 0, SEEK_SET) //get back to the beginning
int location = lseek(fd, 0, SEEK_END) //reach to the end

但是,在文件位置被重置后,每当我尝试使用 read() 时,read() 的返回值总是设置为 -1,这意味着有问题。此外,我收到的 errno 消息是错误的文件描述符。有谁知道我该怎么办?

PS:我试图关闭并重新打开文件以帮助我回到文件的开头并且它有效。但是我不知道如何在不使用 lseek() 的情况下到达文件末尾并以相反的顺序读取整个文件。

另外:一个可重现的例子是:

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    int fd;
    char buffer[1000];

    fd = creat("newFile", 0777);

    memset(buffer, 'a', 500);
    write(fd, buffer, 500); // fill up

    int location = lseek(fd, 0, SEEK_SET); //get back to the beginning

    int read_bytes = read(fd, buffer, 500);
    // this should return the bytes it reads but it actually returns -1
    printf("%d\n", read_bytes);
    return 0;
}

【问题讨论】:

  • 请给出一个完整的可编译示例,这两行代码无法解释问题
  • 也许你也应该检查lseek的返回值
  • @Fred 可重现的示例必须有一个main 函数并且没有语法错误。这意味着一个完整的程序
  • lseek() 的返回值似乎不错。它应该是新的文件位置。

标签: c system-calls lseek


【解决方案1】:

creat 函数不允许您从文件中读取。它只允许你写它。

来自creat(2)

creat()
调用creat() 相当于调用open(),而flags 等于O_CREAT|O_WRONLY|O_TRUNC

这里重要的部分是O_WRONLY。这意味着“只写”。

如果你想打开文件(并创建它)进行读写,那么你可以像这样使用open

int fd = open("newFile", O_CREAT|O_RDWR|O_TRUNC, 0777);

这里重要的部分是O_RDWR。这意味着“读写”。
如果你想让open 在文件已经存在的情况下给出错误,请添加O_EXCL 标志;这会导致返回 -1 并将 errno 设置为 EEXIST(如果您尝试创建该文件时该文件已存在)。

【讨论】:

  • 所以在我创建了一个文件并在其中写入了一些内容之后,我应该先使用 open(),然后才能使用 read()?但我认为我指定为 0777 的第二个参数已经赋予了我读、写和执行的权限。
  • @Fred 您可以首先使用open() 和正确的标志打开它进行读写
  • @Fred 这些只是文件的权限。您仍然需要open 具有足够权限的文件。
【解决方案2】:

以下建议代码:

  1. 干净编译
  2. 正确声明变量类型
  3. 正确创建文件
  4. 正确包含所需的头文件
  5. 正确检查来自 C 库函数的错误指示(并正确处理任何错误)

现在,建议的代码:

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <string.h>
#include <unistd.h>

int main(void)
{
    int fd;
    char buffer[1000];

    // fd = creat("newFile", 0777);
    fd = open("newFile", O_CREAT|O_RDWR|O_TRUNC, 0777);
    if( fd < 0 )
    {
        perror( "open failed" );
        exit( EXIT_FAILURE );
    }

    memset(buffer, 'a', 500);
    write(fd, buffer, 500); // fill up

    off_t location = lseek(fd, 0, SEEK_SET); //get back to the beginning

    printf( "%ld\n", location );

    ssize_t read_bytes = read(fd, buffer, 500);

    if( read_bytes < 0 )
    {
        perror( "read failed" );
        exit( EXIT_FAILURE );
    }


    // this should return the bytes it reads but it actually returns -1
    printf("%ld\n", read_bytes);

    return 0;
}

程序运行结果:

0
500

建议阅读/理解代码使用的任何 C 库函数的 MAN 页面

【讨论】:

  • BZZT 错误:__off_t location。只需将_POSIX_C_SOURCE 定义为适当的值并使用off_t
  • @JL2210,根据 MA​​N 页面,lseek() 返回的类型是 __off_t 并且发布的代码运行时没有警告、错误
  • 那么该手册页有问题。 __off_t 是 glibc 特有的。
  • 这是来自 Linux 手册页的定义:off_t lseek(int fd, off_t offset, int whence);
  • __off_t 不可移植,所以我建议off_t
猜你喜欢
  • 2017-10-07
  • 2019-04-07
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 2018-12-04
  • 2015-11-21
  • 2013-08-06
  • 2016-02-02
相关资源
最近更新 更多