为什么在阅读txt文件时会出现笑脸字符?

时间:2015-10-15 03:14:31

标签: c fopen

我正在尝试不断阅读文本文件,但我不知道我在这里做错了什么。它不断给我打印一些不可打印的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-

输出如下:

enter image description here

2 个答案:

答案 0 :(得分:2)

问题在于:

puts(buff);

read()返回0时,表示您已到达文件的末尾,因此无法打印。您已经在循环的前一次迭代中打印了文件的内容,其中包含:

write(STDOUT_FILENO, buff, n)

puts()正在打印buff中发生的任何垃圾。由于buff不是以空值终止的,因此它可以继续打印远远超过数组的末尾,直到它找到一个空字节。

摆脱那条线。

您不打印文件内容的原因是因为在开始时您会这样做:

lseek(fd, 0, SEEK_END)

这会在尝试读取任何内容之前到达文件的末尾。因此,您的程序将只显示在启动程序后添加到文件的内容。由于sleep(100),它会在打印下一个块之前等待100秒。

答案 1 :(得分:0)

主要问题是lseek()将文件指针放在文件的末尾。

然后所有后续的读取操作都试图读取文件的末尾。

实际上没有读取任何内容,因此输入缓冲区保持不变。

建议删除对lseek()的调用,以便使用调用open()(将文件指针放在文件开头)的结果。

然后调用read()将正确获取文件内容的连续块。

这一行:if (n == 0)说,如果没有读到的话。但是,read()返回的0表示“文件结束”。所以你真正想要的是if (n > 0),这意味着从文件中读取了一些字节。

行:puts(buff);只会输出字符,直到遇到NUL字节。但是,read()不会使用NUL字节终止输入缓冲区,因此对puts()的调用可能会输出超出buff []数组末尾的字符,从而导致未定义的行为。

强烈建议1)插入,在read()之后,buff [n] ='\ 0'或2)使用fgets()从缓冲区中读取行,因为fgets()会使用NUL附加缓冲区字节。