我正在考虑使用read()函数读取整个数据结构,每个数据结构与其他数据结构的类型相同,但具有不同的数据,然后将它们放入链表中。出于某种原因,我似乎无法找到有关如何终止包含read(fp, &tmp, sizeof(struct foo))
后跟new_node(tmp)
的循环的任何具体信息。
我希望能够简单地阅读直到EOF,但我不知道如何使用read()函数来确定EOF。显然,我可以使用write()函数的解决方法,其中我将在写入之前包含文件中的结构数,然后在我达到该数字时终止读取函数,但这看起来有点笨重,并且避免了原始了解文件何时终止的想法。
后续:
我很感激你的帮助,我实施了我所看到的。不幸的是,我相信我可能正在阅读错误的信息。相关代码:
struct test_t{
int data;
char buf[LEN];
struct test_t * next;
};
struct test_t * new_node(struct test_t node, struct test_t * tail)
{
struct test_t * tmp = NULL;
if(!(tmp = malloc(sizeof(struct test_t))))
return NULL;
tmp->data = node.data;
strcpy(tmp->buf, node.buf);
tmp->next = NULL;
if(tail)
tail->next = tmp;
return tmp;
}
...
while(read(fd, &tmp, sizeof(struct test_t)) == sizeof(struct test_t)){
printf("%d, %s\n", tmp.data, tmp.buf);
tail = new_node(tmp, tail);
if(head == NULL)
head = tail;
printf("%d, %s\n", tail->data, tail->buf);
}
...
fd = open("test.txt", O_WRONLY | O_CREAT, 0666);
iter = head;
while(iter){
printf("%d\n", write(fd, &iter, sizeof(struct test_t)));
printf("%d, %s\n", iter->data, iter->buf);
iter = iter->next;
}
这是写循环的输出:
112
1, a
112
2, b
112
3, c
112
4, d
112
5, e
文件以二进制文件保存,但我可以知道只有尾巴似乎写了五次。我不确定为什么会这样。
读取循环中诊断printf的输出是:
23728144,
23728144,
23728272,
23728272,
23728400,
23728400,
23728528,
23728528,
23728656,
23728656,
输出让我觉得它将下一个指针的值放入数据int中。知道为什么: 1)我可能连续五次写同一个节点? 2)当我读()时,我会变得胡言乱语。
答案 0 :(得分:2)
while (read(fd, &tmp, sizeof(tmp)) == sizeof(tmp))
{
...got another one...
}
通常使用FILE *fp;
和int fd;
(因此文件描述符的名称为fd
而不是fp
)。
read()
函数返回它读取的字节数。如果没有更多的数据,则返回0.对于磁盘文件等,它将返回请求的字节数(除非在可能没有剩余的字节需要读取的最末端)或0时没有数据读取(如果设备上有错误,则返回-1,而不是只读取数据)。对于终端(以及套接字和管道),它将读取尽可能多的字节而不是等待请求的大小(因此每次读取可以返回不同的大小)。显示的代码只读取全尺寸结构和填充,如果它得到短读,EOF或错误。
ensc中answer的代码涵盖了所有实际情况,但不是我编写等效循环的方式。我会用:
struct foo tmp;
ssize_t nbytes;
while ((nbytes = read(fd, &tmp, sizeof(tmp))) != 0)
{
if ((size_t)nbytes = sizeof(tmp))
process(&tmp);
else if (nbytes < 0 && errno == EINTR)
continue;
else if (nbytes > 0)
err_syserr("Short read of %zu bytes when %zu expected on fd %d\n",
nbytes, sizeof(tmp), fd);
else
err_syserr("Read failure on fd %d\n", fd);
}
两个正常情况 - 读取全长记录OK并检测到EOF - 在循环顶部处理;深奥的案件在循环中进一步处理。我的err_syserr()
函数是printf()
- 并且报告其参数给出的错误,以及与errno
相关的错误(如果它不为零),然后退出。您可以使用任何等效机制。我可能会也可能不会将文件描述符号放在错误消息中;这取决于谁将会看到错误。如果我知道文件名,我肯定会在消息中包含它而不是文件描述符。
我认为处理nbytes == -1 && errno == EINTR
案件没有任何困难,这与@ensc的评论相反。
答案 1 :(得分:2)
read返回读取的字节数。如果执行读取,并且返回值小于您请求的字节数,那么您知道它在读取期间达到了EOF。如果它完全等于请求的字节数,那么文件没有达到EOF,或者它已经完成,文件中还剩下0个字节,在这种情况下,下一次调用read()将返回0。
while(read(fd, &tmp, sizeof(tmp)) > 0) {
...
}
答案 2 :(得分:2)
for (;;) {
struct foo tmp;
ssize_t l = read(fd, &tmp, sizeof tmp);
if (l < 0 && errno == EINTR) {
continue;
} else if (l < 0) {
perror("read()");
abort();
} else if (l == 0) {
break; /* eof condition */
} else if ((size_t)(l) != sizeof tmp) {
abort(); /* something odd happened */
} else {
handle(&tmp);
}
}
编辑:
在我的项目中,我使用通用
bool read_all(int fd, void *dst_, size_t len, bool *is_err)
{
unsigned char *dst = dst_;
*is_err = false;
while (len > 0) {
ssize_t l = read(fd, dst, len);
if (l > 0) {
dst += l;
len -= l;
} else if (l == 0) {
com_err("read_all", 0, "read(): EOF");
*is_err = (void *)dst != dst_;
break;
} else if (errno == EINTR) {
continue;
} else {
com_err("read_all", errno, "read()");
*is_err = true;
break;
}
}
return len == 0;
}
功能。 因为我更喜欢使用方法来说明要读取多少元素,所以您可以使用上面的EOF
在此处理为错误。但是,在非EOF错误情况下设置的函数中添加另一个bool *err
参数将是微不足道的。
while (read_all(fd, &tmp, sizeof tmp, &is_err))
new_node(&tmp);
答案 3 :(得分:2)
忽略错误情况,我认为这是基本的想法:
while (read(fp, &tmp, sizeof(struct foo))==sizeof(struct foo))
new_node(tmp);