C语言 我可以使用read from unistd. h从文件读入一个结构体吗?

yeotifhr  于 2023-02-07  发布在  其他
关注(0)|答案(3)|浏览(118)

我在努力做两件事:从一个文件描述符读入一个结构体,然后我需要读入一个内存位置。对于第一个,我使用fread。对于第二个,我使用read from unistd. h。
有没有什么方法可以做到这两点,而不需要像这样使用fopen,fclose,open,close和repeating?我可以使用“read”来读入一个结构体吗?

doinxwow

doinxwow1#

调用fopen()后,可以通过fileno()获取文件指针的文件描述符,如下所示:

int fd;
fd = fileno (fp);

然后你可以直接使用read。事实上,fopen()open()都为进程打开一个文件,前者返回一个指向文件的指针,而后者返回文件描述符。FILE类型只是一个struct,它有一个字段记录底层文件描述符。
换句话说,在类Unix系统上,fopen()是使用open()实现的,因此必须有一种方法同时使用这两个调用。
注意,在我的系统(wsl2)上,FILE的定义可以在路径/usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h下找到,如下所示:

struct _IO_FILE
{
  /* ... */
  int _fileno;
  /* ... */
};
cpjpxq1n

cpjpxq1n2#

是的,当然你可以把数据(这里是字符串)读入一个结构体:

#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);
}
b1uwtaje

b1uwtaje3#

回复:有没有什么方法可以做到这两点,而不需要像这样重复fopen、fclose、open、close?
可以。您可以使用fileno()获取与FILE *对应的文件描述符。从手册页中可以看到:
函数fileno()检查参数流,并返回用于实现该流的整数文件描述符,该文件描述符仍然归stream所有,并将在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()将文件Map到内存并使用它可能会更高效。
[1]- EBADFfd不是有效的文件描述符或未打开以供读取。

相关问题