我正在编写一个应用程序,我必须在其中解析文件的内容。我正在使用一些与动态分配的数组不兼容的库函数。这迫使我在堆栈上有一个固定大小的数组。但是,如果仅部分读取行并且我被迫使用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不是确定文件大小的可靠方法?
答案 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()
来电。