我需要读取文件并将它们存储在mainbuff和mainbuff2中。
我应该只使用系统调用open()
, read()
, write()
等。
我不想把它们堆放在一起,如果它会很大? 堆分配更好。
这段代码的作品:
... char charbuf; char *mainbuff1=malloc(100); char *mainbuff2=malloc(100); while (read(file1, &charbuf, 1)!=0) mainbuff1[len++]=charbuf; while (read(file2, &charbuf, 1)!=0) mainbuff2[len2++]=charbuf; ...
但是mainbuff只有100个字符。 像这样更好的解决方法是在文件计数字符后分配mainbuff:
... char charbuf; while (read(file1, &charbuf, 1)!=0) len++; while (read(file2, &charbuf, 1)!=0) len2++; char *mainbuff1=malloc(len); char *mainbuff2=malloc(len2); ...
然后再次重复while
循环和读取字节到mainbuff中。
但是,2个循环(首先会读取和计数,第二个会读取)对于大文件来说将是无效的和慢的。 需要在一个或另一个更有效的做。 请帮忙! 不知道!
您可以使用fstat
来获取文件大小而不是读取两次。
#include <sys/stat.h> int main() { struct stat sbuf; int fd = open("filename", O_RDWR); fstat(fd, &sbuf); char *buf = malloc(sbuf.st_size + 1); }
但是,真正担心效率的时间是在它工作得太慢之后。
如果这确实是一个需要优化的地方,那么你应该优化的是以下两点:
read()
的调用次数read()
和write()
对于100到1000字节的小缓冲区,没有理由使用malloc()
之类的东西,只是在栈上分配缓冲区,这将是最快的。 当然,除非你想从函数返回指向这些缓冲区的指针,在这种情况下,你可能应该使用malloc()
。 否则,你应该考虑使用全局/静态数组,而不是动态分配的数组。
至于I / O调用,用整个缓冲区大小调用read()
和write()
。 不要叫他们读或写单个字节。 转向内核和后退确实有成本。
此外,如果您希望在RAM中使用相当大的文件,请考虑使用文件映射。
stat
等人 允许您获取文件大小。 http://linux.die.net/man/2/fstat
或者,如果你不能使用那个, lseek
http://linux.die.net/man/2/lseek (特别注意返回值)
如果你不能使用它,你可以随时重新realloc
你的缓冲区。
因为这显然是一项任务,所以我把它留给你来实施。 ;)
在优化任何事情之前,你必须分析你的代码 。 许多工具可以做到这一点:
定义一个自动直接扩展的数组。 喜欢这个
#include <stdio.h> #include <stdlib.h> typedef struct dynarray { size_t size; size_t capacity; char *array; } DynArray; DynArray *da_make(size_t init_size){ DynArray *da; if(NULL==(da=(DynArray*)malloc(sizeof(DynArray)))){ perror("memory not enough"); exit(-1); } if(NULL==(da->array=(char*)malloc(sizeof(char)*init_size))){ perror("memory not enough"); exit(-1); } da->size = 0; da->capacity=init_size; return da; } void da_add(DynArray *da, char value){ da->array[da->size] = value; if(++da->size == da->capacity){ da->array=(char*)realloc(da->array, sizeof(char)*(da->capacity += 1024)); if(NULL==da){ perror("memory not enough"); exit(-1); } } } void da_free(DynArray *da){ free(da->array); free(da); } int main(void) { DynArray *da; char charbuf; int i; da = da_make(128); while(read(0, &charbuf, 1)!=0) da_add(da, charbuf); for(i=0;i<da->size;++i) putchar(da->array[i]); da_free(da); return 0; }
为什么你需要记忆中的一切? 你可以有大块的读取,处理,读下一个块等,
除非你有足够的记忆力,否则你不能把所有的东西放在你的爱好者身上 你的目标是什么?
如果像你说的那样,你只使用系统调用 ,那么你可能会把整个堆作为缓冲区。
#include <unistd.h> #include <signal.h> #include <stdio.h> #include <sys/types.h> #include <fcntl.h> size_t sz; void fix(x){signal(SIGSEGV,fix);sbrk(sz *= 2);} int main() { sz = getpagesize(); signal(SIGSEGV,fix); char *buf = sbrk(sz); int fd = open("filename", O_RDWR); read(fd, buf, -1); }
但是如果你碰巧调用一个使用malloc的库函数,Kablooey!
brk
和sbrk
函数使您可以直接访问malloc使用的同一个堆。 但没有任何malloc的“开销”。 没有任何malloc的功能 ,如free
, realloc
。 sbrk
以字节大小调用并返回一个void *
。 brk
被调用了一个指针值(也就是说,你可以把这个指针想象成一个存在的方法,并以一种方式将其声明为brk
),并返回一个void *
。
通过使用brk
或sbrk
来分配内存,它使用malloc将尝试设置并在第一次调用malloc
或realloc
时使用的空间。 许多库函数在底层使用malloc,所以这个代码有很多方法可以打破。 这是一个非常奇怪和有趣的领域。
这里的信号处理程序也是非常危险的。 它给你自动无限的空间,但是当然,如果你遇到任何其他类型的分割违例,像解引用NULL指针,处理程序不能修复,并且不能再崩溃。 所以这可以将程序发送到令人讨厌的循环:重试内存访问,分配更多空间,重试内存访问,分配更多空间。