为什么我在读取 txt 文件时会出现笑脸字符?
Why do I get smiley characters while reading a txt file?
我正在尝试连续读取文本文件,但我不知道自己做错了什么。它一直给我打印一些不可打印的 ascii 字符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include "windows.h"
int main(int argc, char **argv)
{
int n, fd;
char buff[256];
if (argc != 2)
{
fprintf(stderr, "usage: %s <filename>\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0)
{
perror("open");
return 1;
}
else if (lseek(fd, 0, SEEK_END) < 0)
{
perror("lseek");
return 1;
}
else
{
while (1)
{
n = read(fd, buff, sizeof(buff));
if (n < 0)
{
perror("read");
break;
}
if (n == 0)
{
puts(buff);
Sleep(100);
continue;
}
if (write(STDOUT_FILENO, buff, n) < 0)
{
perror("write");
break;
}
}
}
return 0;
}
至于我的论点,我传递了一个包含如下信息的文件名:
foo-12-
输出是这样的:
问题在于线路:
puts(buff);
当read()
returns 0
时,表示您已到达文件末尾,因此没有可打印的内容。您已经在之前的循环迭代中打印了文件的内容,在以下行:
write(STDOUT_FILENO, buff, n)
puts()
正在打印 buff
中的任何垃圾。由于 buff
不是空终止的,它可能会继续打印远远超过数组的末尾,直到找到空字节。
去掉那一行。
你不打印文件内容的原因是因为一开始你做了:
lseek(fd, 0, SEEK_END)
这会在尝试读取任何内容之前到达文件末尾。因此,您的程序只会显示在您启动程序后添加到文件中的内容。因为 sleep(100)
,它会在打印下一个块之前等待 100 秒。
主要问题是 lseek()
将文件指针放在文件末尾。
然后所有后续读取操作都试图读取文件末尾。
实际上没有读取任何内容,因此输入缓冲区未更改。
建议删除对 lseek()
的调用,以便使用对 open()
的调用结果(将文件指针置于文件开头)。
然后调用 read()
将正确获取文件内容的连续块。
这一行:if (n == 0)
表示,如果未读取任何内容。然而,从 read() 返回的 0 表示 'end of file'。所以你真正想要的是 if (n > 0)
这意味着从文件中读取了一些字节。
行:puts(buff);
只会输出字符,直到遇到 NUL 字节。但是,read()
不会以 NUL 字节终止输入缓冲区,因此对 puts() 的调用可能会输出超过 buff[] 数组末尾的字符,从而导致未定义的行为。
强烈建议 1) 在 read() 之后插入 buff[n] = '\0' 或 2) 使用 fgets() 从缓冲区中读取行,因为 fgets() 会在缓冲区中附加一个 NUL 字节。
我正在尝试连续读取文本文件,但我不知道自己做错了什么。它一直给我打印一些不可打印的 ascii 字符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include "windows.h"
int main(int argc, char **argv)
{
int n, fd;
char buff[256];
if (argc != 2)
{
fprintf(stderr, "usage: %s <filename>\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0)
{
perror("open");
return 1;
}
else if (lseek(fd, 0, SEEK_END) < 0)
{
perror("lseek");
return 1;
}
else
{
while (1)
{
n = read(fd, buff, sizeof(buff));
if (n < 0)
{
perror("read");
break;
}
if (n == 0)
{
puts(buff);
Sleep(100);
continue;
}
if (write(STDOUT_FILENO, buff, n) < 0)
{
perror("write");
break;
}
}
}
return 0;
}
至于我的论点,我传递了一个包含如下信息的文件名:
foo-12-
输出是这样的:
问题在于线路:
puts(buff);
当read()
returns 0
时,表示您已到达文件末尾,因此没有可打印的内容。您已经在之前的循环迭代中打印了文件的内容,在以下行:
write(STDOUT_FILENO, buff, n)
puts()
正在打印 buff
中的任何垃圾。由于 buff
不是空终止的,它可能会继续打印远远超过数组的末尾,直到找到空字节。
去掉那一行。
你不打印文件内容的原因是因为一开始你做了:
lseek(fd, 0, SEEK_END)
这会在尝试读取任何内容之前到达文件末尾。因此,您的程序只会显示在您启动程序后添加到文件中的内容。因为 sleep(100)
,它会在打印下一个块之前等待 100 秒。
主要问题是 lseek()
将文件指针放在文件末尾。
然后所有后续读取操作都试图读取文件末尾。
实际上没有读取任何内容,因此输入缓冲区未更改。
建议删除对 lseek()
的调用,以便使用对 open()
的调用结果(将文件指针置于文件开头)。
然后调用 read()
将正确获取文件内容的连续块。
这一行:if (n == 0)
表示,如果未读取任何内容。然而,从 read() 返回的 0 表示 'end of file'。所以你真正想要的是 if (n > 0)
这意味着从文件中读取了一些字节。
行:puts(buff);
只会输出字符,直到遇到 NUL 字节。但是,read()
不会以 NUL 字节终止输入缓冲区,因此对 puts() 的调用可能会输出超过 buff[] 数组末尾的字符,从而导致未定义的行为。
强烈建议 1) 在 read() 之后插入 buff[n] = '\0' 或 2) 使用 fgets() 从缓冲区中读取行,因为 fgets() 会在缓冲区中附加一个 NUL 字节。