C中更快的I/O

C中更快的I/O,c,optimization,io,C,Optimization,Io,我有一个问题,这将采取1000000行输入如下从控制台 0 1 23 4 5 1 3 5 2 56 12 2 3 33 5 ... ... 我用过scanf,但速度很慢。是否有其他方法可以更快地从控制台获取输入?我可以使用read(),但我不确定每行中的字节数,因此我不能像read()那样读取“n”个字节。 谢谢 非常感谢您使用多个具有固定大小缓冲区的读取,直到到达文件末尾。出于好奇,是什么在控制台中生成了这么多行,那么快呢?一次读取一行(如果缓冲区不够大,请使用较大的缓冲区展开并继续) 然后

我有一个问题,这将采取1000000行输入如下从控制台

0 1 23 4 5
1 3 5 2 56
12 2 3 33 5
...
...
我用过scanf,但速度很慢。是否有其他方法可以更快地从控制台获取输入?我可以使用read(),但我不确定每行中的字节数,因此我不能像read()那样读取“n”个字节。 谢谢
非常感谢您使用多个具有固定大小缓冲区的
读取
,直到到达文件末尾。

出于好奇,是什么在控制台中生成了这么多行,那么快呢?

一次读取一行(如果缓冲区不够大,请使用较大的缓冲区展开并继续)

然后使用专用功能(如atoi)而不是通用功能进行转换

但是,最重要的是,设置一个可重复的测试线束,并对其进行分析,以确保更改确实加快了速度。

使用fgets(…)一次拉一条线。请注意,您应该检查行末尾的“\n”,如果没有,则表示您处于EOF,或者需要读取另一个缓冲区的值,并将两者连接在一起。起泡,冲洗,重复。不要被缓冲区溢出抓住

然后,您可以自己解析内存中的每个逻辑行。我喜欢用strspn(…)和strcspn(…)来做这类事情,但是你的里程数可能会有所不同

解析:
定义分隔符字符串。使用strspn()计算与分隔符匹配的“非数据”字符,并跳过它们。使用strcspn()计算与分隔符不匹配的“数据”字符。如果此计数为0,则完成(行中没有更多数据)。否则,将这些N个字符复制到一个解析函数,如atoi(…)或sscanf(…)。然后,将指针基重置到此块的末尾,并重复跳过delims、复制数据、转换为数字的过程。

如果您的示例具有代表性,即每行有五个十进制数字的固定格式,我可能会使用
fgets()
的组合来读取行,然后使用一个调用
strtol()的循环
将字符串转换为整数

这应该比
scanf()
更快,同时比单独进行字符串到整数的转换更清晰、更高级

大概是这样的:

typedef struct {
  int number[5];
} LineOfNumbers;

int getNumbers(FILE *in, LineOfNumbers *line)
{
  char buf[128];  /* Should be large enough. */
  if(fgets(buf, sizeof buf, in) != NULL)
  {
    int i;
    char *ptr, *eptr;

    ptr = buf;
    for(i = 0; i < sizeof line->number / sizeof *line->number; i++)
    {
      line->number[i] = (int) strtol(ptr, &eptr, 10);
      if(eptr == ptr)
        return 0;
      ptr = eptr;
    }
    return 1;
  }
  return 0;
}
typedef结构{
整数[5];
}数字线;
int getNumbers(文件*in,编号行*line)
{
char buf[128];/*应该足够大*/
if(fgets(buf,sizeof buf,in)!=NULL)
{
int i;
字符*ptr,*eptr;
ptr=buf;
对于(i=0;inumber/sizeof*line->number;i++)
{
行->编号[i]=(int)strtol(ptr和eptr,10);
如果(eptr==ptr)
返回0;
ptr=eptr;
}
返回1;
}
返回0;
}

注意:这是未经测试(甚至未编译!)的浏览器编写代码。但作为一个具体的例子,它可能很有用。

如果可以,请使用二进制I/O。文本转换会使阅读速度降低几倍。如果您使用文本I/O,因为它易于调试,请再次考虑二进制格式,并使用OD程序(假设您在UNIX上)在需要时使其成为人类可读的。
哦,还有一件事:AT&T的SFIO库,它代表更安全/更快的文件IO。您可能在这方面也有一些运气,但我怀疑您是否会获得与二进制格式相同的加速。

如果您尝试读取的字节数超过了字节数,fread仍将返回

我发现读取文件的最快方法如下:

typedef struct {
  int number[5];
} LineOfNumbers;

int getNumbers(FILE *in, LineOfNumbers *line)
{
  char buf[128];  /* Should be large enough. */
  if(fgets(buf, sizeof buf, in) != NULL)
  {
    int i;
    char *ptr, *eptr;

    ptr = buf;
    for(i = 0; i < sizeof line->number / sizeof *line->number; i++)
    {
      line->number[i] = (int) strtol(ptr, &eptr, 10);
      if(eptr == ptr)
        return 0;
      ptr = eptr;
    }
    return 1;
  }
  return 0;
}
/*查找文件结尾*/ fseek(文件,0,SEEK_END)

/*获取文件大小*/ 大小=ftell(文件)

/*查找文件的开头*/ fseek(文件,0,搜索集)

/*为文件创建缓冲区*/ 缓冲区=malloc(1048576)

/*每次刷新1MB,直到达到大小字节等*/

在现代计算机上,使用ram并将整个内容加载到ram中,然后您可以轻松地通过内存工作


至少您应该使用fread,块大小尽可能大,并且至少与缓存块或HDD扇区大小一样大(最小4096字节,我个人将使用1048576字节)。您会发现,对于更大的读取需求,rfead能够在一次操作中按顺序获得大数据流。这里有人建议使用128字节,这真是不可思议。。。。由于调用之间的微小延迟将导致磁头已经通过下一个扇区,几乎可以肯定该扇区具有您所需的顺序数据,因此驱动器必须始终进行搜索。

通过使用
fread()
fread\u unlocked()
(如果您的程序是单线程的)。锁定/解锁输入流一次所需的时间可以忽略不计,因此忽略这一点

代码如下:

#include <iostream>

int maxio=1000000;
char buf[maxio], *s = buf + maxio;

inline char getc1(void)
{
   if(s >= buf + maxio) { fread_unlocked(buf,sizeof(char),maxio,stdin); s = buf; }
   return *(s++);
}
inline int input()
{
   char t = getc1();
   int n=1,res=0;
   while(t!='-' && !isdigit(t)) t=getc1(); if(t=='-')
   {
      n=-1; t=getc1();
   }
   while(isdigit(t))
   {
     res = 10*res + (t&15);
     t=getc1();
   }
   return res*n;
}
#包括
int maxio=1000000;
字符buf[maxio],*s=buf+maxio;
内联字符getc1(void)
{
如果(s>=buf+maxio){fread_解锁(buf,sizeof(char),maxio,stdin);s=buf;}
返回*(s++);
}
内联int输入()
{
chart=getc1();
int n=1,res=0;
while(t!='-'&&!isdigit(t))t=getc1();if(t=='-'))
{
n=-1;t=getc1();
}
while(isdigit(t))
{
res=10*res+(t&15);
t=getc1();
}
返回res*n;
}
这是在
C++
中实现的。在
C
中,不需要包含
iostream
,函数
isdigit()
是隐式可用的

您可以通过调用
getc1()
将输入作为一个字符流,并通过调用
input()
获取整数输入

使用
fread()
的整个想法是一次获取所有输入。调用
scanf()/printf()
,在锁定和解锁流时重复占用宝贵的时间,这在单线程程序中是完全冗余的

还要确保
maxio
的值使得所有输入只能在几次“往返”中进行(在这种情况下,最好是一次)。根据需要进行调整


希望这有帮助!

%a.out