代码之家  ›  专栏  ›  技术社区  ›  JobHunter69

C: 我可以使用从unistd.h读取文件到结构中吗?

  •  0
  • JobHunter69  · 技术社区  · 3 年前

    我正在尝试做两件事:从文件描述符读取到结构中,然后我需要读取到内存位置。第一次,我使用fread。这是我第二次使用从unistd.h读取。

    有没有什么我可以做到这两件事而不需要像这样打开、关闭、打开、关闭和重复?我能用“read”读结构吗?

    0 回复  |  直到 3 年前
        1
  •  1
  •   Wert    3 年前

    打电话后 fopen() ,您可以通过 fileno() ,如下所示:

    int fd;
    fd = fileno (fp);
    

    然后你可以使用 read 直接地事实上,两者 fopen() 和 open() 为进程打开一个文件,前者返回指向该文件的指针,而后者返回文件描述符。这个 FILE 类型只是一个 struct 其具有记录底层文件描述符的字段。

    换句话说,在类unix系统上, fopen() 使用实现 打开() ,所以必须有一种方法可以同时使用这两个调用。

    注意,在我的系统(wsl2)上 文件 可以在路径下找到 /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h ,看起来像这样:

    struct _IO_FILE
    {
      /* ... */
      int _fileno;
      /* ... */
    };
    
        2
  •  0
  •   Allan Wind    3 年前

    是的,当然您可以将数据(此处为字符串)读取到结构中:

    #include <fcntl.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    #define DATA_LEN 1024
    
    struct s {
      char data[DATA_LEN];
    };
    
    int main() {
        int fd = open("1.c", O_RDONLY);
        if(fd == -1) {
            perror("file");
            return 1;
        }
        struct s s;
        ssize_t n = read(fd, s.data, DATA_LEN);
        printf("%.*s\n", (int) n, s.data);
        close(fd);
    }
    
        3
  •  0
  •   Madagascar    3 年前

    回复:不管怎样,我都可以做到吗, 像这样打开、关闭和重复?

    对您可以获得与 FILE * 具有 fileno() 。来自手册页:

    函数fileno()检查参数流并返回 用于实现此流的整数文件描述符。这个 文件描述符仍归流所有,并且将在 调用fclose(3)。

    例如:

    /** 
    *   @brief  Opens the file whose name is the string pointed to 
    *           by file_name and associates a stream with it.
    *   @return A file descriptor corresponding to the stream on success, 
    *           -1 elsewise.
    */
    static int open_sesame (FILE *stream, const char *file_name) 
    {
        stream = fopen (file_name, "r");
        if (!stream) {
            perror ("fopen()");
            /* Handle error here */
            return -1;
        }
        /* On failure, -1 is returned and errno is set to indicate
        *  the error. 
        */
        int fd = fileno (stream);
        if (fd == -1) {
            perror ("fileno()");
            /* Handle error here */
            return -1;
        }
        return fd;
    }
    

    这也可以做到:

    /* read() will return -1 and set errno to EBADF¹ 
    *  if fileno() fails.
    */
    if (read (fileno (fp), ..., ..., ...) == -1) {
        perror ("read()");
        /* Handle error here */
    }
    

    另一方面,如果您想为相应的文件描述符打开一个流,那么 fdopen() 。来自手册页:

    fdopen()函数应将流与文件相关联 描述符。

    示例调用:

    /* Upon successful completion, fdopen() shall return 
    *  a pointer to a stream; otherwise, a null pointer 
    *  shall be returned and errno set to indicate the 
    *  error.
    */
    FILE *stream = fdopen (fd, "r");
    if (!stream) {
        perror ("fdopen()");
        /* Handle error here */
    }
    

    或者,正如@Fe203所建议的,如果您需要两份数据副本,您可以使用标准 memcpy() 而不是从文件中读取两次。或者,由于您已经在使用POSIX系统调用,使用 mmap() 并与之合作。

    [1] EBADF : fd 不是有效的文件描述符,或者未打开以供读取。