C 在不知道行长度的情况下从文件中读取行
我想一行一行地读入一个文件,以前不知道行的长度。以下是我目前得到的信息:C 在不知道行长度的情况下从文件中读取行,c,file-io,C,File Io,我想一行一行地读入一个文件,以前不知道行的长度。以下是我目前得到的信息: int ch = getc(file); int length = 0; char buffer[4095]; while (ch != '\n' && ch != EOF) { ch = getc(file); buffer[length] = ch; length++; } printf("Line length: %d characters.", length); cha
int ch = getc(file);
int length = 0;
char buffer[4095];
while (ch != '\n' && ch != EOF) {
ch = getc(file);
buffer[length] = ch;
length++;
}
printf("Line length: %d characters.", length);
char newbuffer[length + 1];
for (int i = 0; i < length; i++)
newbuffer[i] = buffer[i];
newbuffer[length] = '\0'; // newbuffer now contains the line.
int ch=getc(文件);
整数长度=0;
字符缓冲区[4095];
while(ch!='\n'&&ch!=EOF){
ch=getc(文件);
缓冲区[长度]=ch;
长度++;
}
printf(“行长度:%d个字符”,长度);
char newbuffer[长度+1];
for(int i=0;i
我现在可以计算出行长度,但只适用于短于4095个字符的行,加上两个字符数组似乎是执行任务的一种笨拙方式。
有没有更好的方法可以做到这一点(我已经使用了fgets(),但有人告诉我这不是最好的方法)
--你很接近了。基本上,您希望读取数据块并检查它们是否有
\n
字符。如果你找到了一个,很好,你就完了。如果你不这样做,你必须增加你的缓冲区(即分配一个新的缓冲区,其大小是第一个缓冲区的两倍,并将第一个缓冲区中的数据复制到新的缓冲区中,然后删除旧的缓冲区,并将新的缓冲区重命名为旧的缓冲区——或者如果你是C语言,则只需realloc
),然后再阅读一些内容,直到找到结束
结束后,从缓冲区开始到\n
字符的文本就是您的行。将其复制到缓冲区或就地处理,由您决定
准备好下一行后,可以在当前行上复制输入的“其余部分”(基本上是左移),并用输入的数据填充缓冲区的其余部分。然后再继续,直到数据用完
这当然可以进行优化,例如使用循环缓冲区,但对于任何合理的io绑定算法来说,这应该是足够的。您可以从选择合适的大小开始,然后在需要更多空间时中途使用
realloc
:
int CUR_MAX = 4095;
char *buffer = (char*) malloc(sizeof(char) * CUR_MAX); // allocate buffer.
int length = 0;
while ( (ch != '\n') && (ch != EOF) ) {
if(length ==CUR_MAX) { // time to expand ?
CUR_MAX *= 2; // expand to double the current size of anything similar.
buffer = realloc(buffer, CUR_MAX); // re allocate memory.
}
ch = getc(file); // read from stream.
buffer[length] = ch; // stuff in buffer.
length++;
}
.
.
free(buffer);
在调用
malloc
和realloc
之后,您必须检查分配错误,您可能需要查看。如果您使用的是glibc系统,您可能有一个(非标准)函数可用。这就是我为stdin所做的,如果您像readLine(NULL,0)
那样调用它,该函数将为您分配一个大小为1024的缓冲区,并让它以1024的步长增长。如果使用readLine(NULL,10)
调用函数,将得到一个步骤为10的缓冲区。如果你有一个缓冲区,你可以提供它的大小
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
char *readLine(char **line, size_t *length)
{
assert(line != NULL);
assert(length != NULL);
size_t count = 0;
*length = *length > 0 ? *length : 1024;
if (!*line)
{
*line = calloc(*length, sizeof(**line));
if (!*line)
{
return NULL;
}
}
else
{
memset(*line, 0, *length);
}
for (int ch = getc(stdin); ch != '\n' && ch != EOF; ch = getc(stdin))
{
if (count == *length)
{
*length += 2;
*line = realloc(*line, *length);
if (!*line)
{
return NULL;
}
}
(*line)[count] = (char)ch;
++count;
}
return *line;
}
#包括
#包括
#包括
#包括
字符*读线(字符**行,大小*长度)
{
断言(行!=NULL);
断言(长度!=NULL);
大小\u t计数=0;
*长度=*长度>0?*长度:1024;
如果(!*行)
{
*line=calloc(*长度,sizeof(**行));
如果(!*行)
{
返回NULL;
}
}
其他的
{
memset(*行,0,*长度);
}
对于(int ch=getc(stdin);ch!='\n'&&ch!=EOF;ch=getc(stdin))
{
如果(计数==*长度)
{
*长度+=2;
*行=realloc(*行,*长度);
如果(!*行)
{
返回NULL;
}
}
(*行)[计数]=(字符)ch;
++计数;
}
返回*行;
}
考虑scanf“%m”格式转换修饰符(POSIX)
引用scanf手册页:
可选的“m”字符。
这用于字符串转换
(%s,%c,%[),并释放
需要分配一个相应的缓冲区来保存输入:相反,scanf()分配一个足够的缓冲区
并将此缓冲区的地址分配给相应的指针参数,该参数应该是指向的指针
char*变量(调用前不需要初始化此变量)。调用方随后应在不再需要时释放(3)此缓冲区
值得注意的是,逐字符读取速度非常慢。您应该以大块(4-16k)的形式读取。@Blindy:标准库I/O有缓冲功能,所以这并不多比分块读取慢。将计数重置为0是否会导致缓冲区溢出?请一如既往。为什么在扩大内存大小后将计数重置回0?以前的内存是否仍然存在?很好!我相信我可以相信大多数类UNIX系统都安装了glibc,所以这绝对是一种很好的行读取方式。此外,
getline
已包含在最新的POSIX标准中,因此它现在是unix上的标准。但是,仍然不能保证它本身包含在c中。
char *arr = NULL ;
// Read unlimited string, terminated with newline. Similar to dynamic size fgets.
if ( fscanf(stdin, "%m[^\n]", &arr) == 1 ) {
// Do something with arr
free(arr) ;
} ;