【问题标题】:stdin to stdout after processing处理后标准输入到标准输出
【发布时间】:2017-10-25 14:39:14
【问题描述】:

我有一个实用程序,它应该通过将文件转换为备用文件格式来优化文件。如果它不能使文件更小,我希望返回原始文件。

设计是使用stdin in 和stdout 进行输入和输出。这是针对处理后的大小大于原始文件大小的情况。所有其他分支都经过测试可以正常工作。

  char readbuffer[65536];
  ssize_t readinbytes;
  while ((readinbytes = fread(readbuffer, sizeof(char), insize, stdin)) > 0) {
    if (fwrite(readbuffer, sizeof(char), readnbytes, stdout) != readnbytes) {
      fatal("can't write to stdout, please smash and burn the computer\n");
    }
  }

问题这导致文件大小为 0

【问题讨论】:

  • @PaulOgilvie 鉴于代码看起来“cruft”代表“nothing”。
  • 如何分辨二进制文件中的杂乱无章?
  • 在使用标准输入后,我试图在程序开始时将标准输入原样发送到标准输出。我知道标准输入没有被关闭,但我记得如果之前访问过它是一个 PITA。我尝试 fseek 重置流中的位置,以便我可以从标准输入的第一个字节读取到最后一个字节。一次最多 64k。
  • @WeatherVane 这会尝试将值适合较小的值,检查更改后文件大小是否不同。如果一个文件有太多独特的块,没有保存,所以只是输出文件原样。我不需要编写程序,这种情况我似乎无法破解它
  • OT:sizeof(char) 根据定义等于 1,当您将 sizeof(readbuffer) 作为元素数传递时,您已经在隐式使用该事实。

标签: c stdout stdin


【解决方案1】:

对这个问题有一个奇怪的答案。本质上,我必须将stdin 读入缓冲区(inbuf),然后输出该缓冲区的内容。我没有得到任何输出的首要原因是多方面的。

  1. 首先我没有发现一个已经确定输入缓冲区是否小于输出缓冲区的分支

    if((readinbytes < outbuffersize) || force) {
        // inside this is where the code was...
    
  2. 看起来(因为正在使用 stdout 写入)有一个部分包含一个日志语句,该语句未在匹配的 else 块中输出。继承的代码格式非常糟糕,因此从未被人接受。

    由于输出错误消息不符合实用程序的目的(如果提供了有效的输入文件,则始终输出有效的输出文件)

解决方案stdin在程序开始时被读入inbuf

set_filemode_binary(stdout);
if (fwrite(inbuf, 1, readinbytes, stdout) != insize) {
    fprintf(stderr, "error writing to stdout\n");
    free(inbuf);
    exit(3);
}

勘误表(阅读stdin

unsigned char * inbuf = NULL;
size_t readinbytes;
long insize = 0;

// elsewhere...

// die if no stdin
insize = getFileSize(stdin);
if (insize < 0) {
    fprintf(stderr, "no input to stdin\n");
    exit(2);
}
// read stdin to buffer
inbuf = createBuffer(insize); // wrapper around malloc handling OOM
if ((readinbytes = fread(inbuf, sizeof(char), insize, stdin)) < 0) {
    fprintf(stderr, "error reading from stdin\n");
    free(inbuf);
    exit(3);
}

另外别忘了free(inbuf)

if(inbuf){ free(inbuf); }

我希望这对某人有所帮助。

【讨论】:

  • 还应该注意,有更简单、更广泛兼容的方式来处理缓冲区。此外,您要么需要处理缓冲区溢出,要么需要为 n 长度文件重新分配内存空间(占用 RAM)。我提出的最终解决方案(仍未在上游合并)允许通过 CLI args 设置最大大小的读取字节选项。