C读取函数读取的字节数多于请求的

时间:2017-04-22 16:23:40

标签: c io

我正在尝试使用readstdin读取并将读取的字节发送到stdout并将文件作为参数传递(模仿tee命令)。但是,当我执行:

echo AAAAAAAAAA | ./tee -a file

我得到了

AAAAAAAAAA
Â7þ­hý6þ­hý¥g¢c¾ 
@ERROR: failed to write whole buffer (140726359686392 != 2880)

您可以看到read返回的数字远大于请求的缓冲区大小。 write也写了超过请求的数量,但read返回的数字随每次执行而变化,writes总是返回2880,无论输入的大小如何。

以下是代码:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include <fcntl.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <unistd.h>

#include <string.h>

#define BUFFER_SIZE 64

extern int optind;

void exit_err(char *format, ...)
{
    va_list args;

    fflush(stdout);

    va_start(args, format);
    fprintf(stderr, format, args);
    va_end(args);

    fprintf(stderr, "\n");

    fflush(stderr);
    exit(EXIT_FAILURE);
}

int main(int argc, char *argv[])
{
    if (argc < 2 || strncmp(argv[1], "--help", 6) == 0)
        exit_err("USAGE: %s [-a] [OUTPUTFILE]", argv[0]);

    bool append = false;

    char opt;
    while ((opt = getopt(argc, argv, "a")) != -1) {
        switch (opt)
        {
            case 'a':
                append = true;
                break;
            default: /* ? */
                exit_err("USAGE: %s [-a] [OUTPUTFILE]", argv[0]);
        }
    }

    if (optind >= argc) {
        exit_err("ERROR: expected argument after options");
        exit(EXIT_FAILURE);
    }

    int open_flags = O_WRONLY | O_CREAT;
    if (append)
        open_flags |= O_APPEND;
    else
        open_flags |= O_TRUNC;

    mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP;

    int num_output_files = argc - optind + 1;
    int output_fd[num_output_files];
    output_fd[0] = STDOUT_FILENO;

    int i;
    for (i = 1; i < num_output_files; ++i, ++optind) {
        output_fd[i] = open(argv[optind], open_flags, permissions);
        if (output_fd[i] == -1)
            exit_err("ERROR: failed to open %s", argv[optind]);
    }

    ssize_t num_read, num_written;
    char buffer[BUFFER_SIZE];
    while ((num_read = read(STDIN_FILENO, buffer, BUFFER_SIZE)) > 0)
        for (i = 0; i < num_output_files; ++i)
            if ((num_written = write(output_fd[i], buffer, BUFFER_SIZE)) != num_read)
                exit_err("ERROR: failed to write whole buffer (%zd != %zd)", num_read, num_written);

    if (num_read == -1)
        exit_err("ERROR: failed to read from stdin");

    for (i = 0; i < num_output_files; ++i)
        if (close(output_fd[i]) == -1)
            exit_err("ERROR: failed to close file");

    exit(EXIT_SUCCESS);
}

2 个答案:

答案 0 :(得分:2)

因为当您阅读BUFFER_SIZE时,您正在写num_read个字节。

就这样做吧

while ((num_read = read(STDIN_FILENO, buffer, BUFFER_SIZE)) > 0) {
    for (i = 0; i < num_output_files; ++i) {
        if ((num_written = write(output_fd[i], buffer, num_read)) != num_read) {
            exit_err("ERROR: failed to write whole buffer (%zd != %zd)", num_read, num_written);
        }
    }
}

另外,使用大括号并避免过多的缩进,在这种情况下很难阅读。

答案 1 :(得分:0)

除了写错了大小之外,你的错误信息仍然是垃圾邮件,因为你将va_list传递给了fprintf,这并不是它的期望。您需要在那里拨打vfprintf