【发布时间】:2011-04-24 19:02:59
【问题描述】:
我正在从 C 应用程序中的 bzip2 流中提取数据。随着数据块从解压器中出来,它们可以被写入stdout:
fwrite(buffer, 1, length, stdout);
这很好用。当它被发送到stdout时,我得到了所有的数据。
我不想写信给stdout,而是想在内部以单行块处理此语句的输出:一个以换行符结尾的字符串\n。
我是否将解压缩器流的输出写入另一个缓冲区,一次一个字符,直到遇到换行符,然后调用每行处理函数?这很慢吗?有更聪明的方法吗?谢谢你的建议。
编辑
感谢您的建议。每次我通过输出缓冲区的数据时,我最终创建了一对缓冲区,将剩余部分(输出缓冲区末尾的“存根”)存储在短行缓冲区的开头。
我逐个字符地循环输出缓冲区,并一次处理换行符的数据。无换行符的剩余部分被分配和分配,并复制到下一个流的行缓冲区。似乎realloc 比重复的malloc-free 语句更便宜。
这是我想出的代码:
char bzBuf[BZBUFMAXLEN];
BZFILE *bzFp;
int bzError, bzNBuf;
char bzLineBuf[BZLINEBUFMAXLEN];
char *bzBufRemainder = NULL;
int bzBufPosition, bzLineBufPosition;
bzFp = BZ2_bzReadOpen(&bzError, *fp, 0, 0, NULL, 0); /* http://www.bzip.org/1.0.5/bzip2-manual-1.0.5.html#bzcompress-init */
if (bzError != BZ_OK) {
BZ2_bzReadClose(&bzError, bzFp);
fprintf(stderr, "\n\t[gchr2] - Error: Bzip2 data could not be retrieved\n\n");
return -1;
}
bzError = BZ_OK;
bzLineBufPosition = 0;
while (bzError == BZ_OK) {
bzNBuf = BZ2_bzRead(&bzError, bzFp, bzBuf, sizeof(bzBuf));
if (bzError == BZ_OK || bzError == BZ_STREAM_END) {
if (bzBufRemainder != NULL) {
/* fprintf(stderr, "copying bzBufRemainder to bzLineBuf...\n"); */
strncpy(bzLineBuf, bzBufRemainder, strlen(bzBufRemainder)); /* leave out \0 */
bzLineBufPosition = strlen(bzBufRemainder);
}
for (bzBufPosition = 0; bzBufPosition < bzNBuf; bzBufPosition++) {
bzLineBuf[bzLineBufPosition++] = bzBuf[bzBufPosition];
if (bzBuf[bzBufPosition] == '\n') {
bzLineBuf[bzLineBufPosition] = '\0'; /* terminate bzLineBuf */
/* process the line buffer, e.g. print it out or transform it, etc. */
fprintf(stdout, "%s", bzLineBuf);
bzLineBufPosition = 0; /* reset line buffer position */
}
else if (bzBufPosition == (bzNBuf - 1)) {
bzLineBuf[bzLineBufPosition] = '\0';
if (bzBufRemainder != NULL)
bzBufRemainder = (char *)realloc(bzBufRemainder, bzLineBufPosition);
else
bzBufRemainder = (char *)malloc(bzLineBufPosition);
strncpy(bzBufRemainder, bzLineBuf, bzLineBufPosition);
}
}
}
}
if (bzError != BZ_STREAM_END) {
BZ2_bzReadClose(&bzError, bzFp);
fprintf(stderr, "\n\t[gchr2] - Error: Bzip2 data could not be uncompressed\n\n");
return -1;
} else {
BZ2_bzReadGetUnused(&bzError, bzFp, 0, 0);
BZ2_bzReadClose(&bzError, bzFp);
}
free(bzBufRemainder);
bzBufRemainder = NULL;
非常感谢大家的帮助。这很好用。
【问题讨论】:
-
strtok 可以让您免于检查缓冲区中每个字符的换行符。
-
strtok是我之前尝试过的,但它对我不起作用并且我丢失了数据,因为从 bzip2 解压缩器出来的输出缓冲区被分成一行。我最后失去了那一点。也许我使用不正确。是否有使用strtok允许保留无换行的“存根”,将该存根粘合到下一个输出缓冲区块的开头? -
不,你是对的,strtok 不太适合这里。如果您使用 strtok,您会丢失那一点,并且检查每个字符可能更容易。正如 Opera 所描述的那样,除了手动执行之外,我不知道有任何聪明的方法可以保存那个无换行符的“存根”以供以后使用。对不起,有点误导你:)