使用有限缓冲区大小的posix读取

时间:2014-11-26 16:07:48

标签: c file file-io posix

我正在编写一个应用程序,我必须在其中解析文件的内容。我正在使用一些与动态分配的数组不兼容的库函数。这迫使我在堆栈上有一个固定大小的数组。但是,如果仅部分读取行并且我被迫使用POSIX读取来实现此目的,那么解析数据将不起作用。

char buff[512] = '\0';
int fileHandle = open( scEndOfLinePPSPath , O_RDONLY );

if(-1 != fileHandle)
{
    while( 0 < read(fileHandle, &buff, sizeof(buff) - 1) )
    {
        parse(&buff); /* doesn't play nice with dynamically allocated memory */

第二个我开始尝试限制缓冲区大小,我可能会遇到解析失败的情况,因为文件较大而且只能部分读取一行(所以解析算法只有部分数据可以使用)。

如果读取缓冲区如下图所示结束,则解析算法显然无法获取属性名称,下一次读取将使用属性名称的后半部分:

&LT;节点&GT;属性=“麦

在继续使用POSIX读取的同时,是否有一种优雅的方式来处理这种情况?我知道我可以根据文件大小动态分配内存,但正如我所说,动态分配的内存不适用于解析库。

谢谢!

解决:

感谢大家的投入!问题现在解决了。我能够使用动态内存分配并为整个文件创建足够大的缓冲区。

我正在使用lseek确定文件大小。不知何故,读取API读取的内容比lseek或fstat报告的大小多3个字节,因此分配的缓冲区不足以成功解析。这是否意味着,lseek不是确定文件大小的可靠方法?

2 个答案:

答案 0 :(得分:1)

问题在于,您通常不知道您要阅读的行多长时间 - 您需要先阅读它们并查找新行,此时您可能已阅读过部分内容下一行也是如此,所以你需要确保你不会失去它。因此,您最终需要循环读取缓冲区的代码,同时还要在缓冲区中的新行之后查找换行符和移动数据。

所以你通常会得到类似的东西:

char buffer[512];
char *data_start = buffer, *data_end = buffer;

while(1) {
    if (char *eol = memchr(data_start, '\n', data_end-data_start)) {
        /* have a full line, null-terminate and pass to parse */
        *eol = '\0';
        parse(data_start);
        data_start = eol+1;
    } else {
        /* no newline in the buffer -- read more */
        if (data_start != buffer) {
            /* move leftover data (if any) to the front of the buffer */
            memmove(buffer, data_start, data_end - data_start);
            data_end -= data_start-buffer;
            data_start = buffer; }
        if (data_end == buffer + sizeof(buffer)) {
            /* line too long for the buffer -- can't deal with it */
            break; }
        int rv = read(fd, data_end, buffer+sizeof(buffer)-data_end);
        if (rv <= 0) {
            /* error or end of file */
            break; }
        data_end += rv; } }

你可以避免过长时间&#34;当缓冲区已满并且没有新行时,使用您增长的动态缓冲区(可能是大小加倍)会出现问题。

答案 1 :(得分:0)

parse()函数不能区分动态分配的缓冲区和声明为固定大小的数组的缓冲区。但是,它可能期望缓冲区具有特定大小。在这种情况下,处理穿过缓冲区边界的数据(可能需要多次调用)是parse()函数的问题,但是 问题是确保缓冲区的是预期的大小,并在每次调用之前完全填充(除了在文件结尾处,必须以某种方式向parse()发信号通知)。 read()函数不保证这样做,这可能是您的问题。

如果要将所有可用字节读入缓冲区,直到其容量,那么您需要准备执行多个read()。它看起来像这样:

#define BUFF_SIZE 512

char buff[BUFF_SIZE];
ssize_t next_offset = 0;

do {
    ssize_t n_read = read(fd, buff + next_offset, BUFF_SIZE - next_offset);

    if (n_read == 0) {
        /* end of file */
        buff[next_offset] = 0;  /* add a terminator */
        break;
    } else if (n_read < 0) {
        /* handle error ... */
    } else {
        next_offset += n_read;
    }
} while (next_offset < BUFF_SIZE);

或者,问题可能只是parse()期望(零终止)C字符串。如果静态声明缓冲区并初始化它的任何部分,那么未明确初始化的元素将自动使用&#39; \ 0&#39;进行初始化。如果缓冲区恰好大于你的输入,那么它会半自动地给你一个终结符,但是如果你的输入恰好是你的缓冲区的大小或者更长,那么你就会受到冲击。另一方面,使用动态分配的缓冲区,您需要为终结器留出空间,并且需要手动将其插入到末尾。 (如上所述,您仍然需要准备好执行多个read()来电。