优化我的read()循环C(两个循环合二为一)

时间:2013-04-21 09:21:23

标签: c++ c linux unix

我需要读取文件并将它们存储在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个循环(第一个将读取并计数,第二个将读取)对于大型文件将是无效且慢的。需要在一个或更高效的其他方面做到这一点。请帮忙!不知道!

7 个答案:

答案 0 :(得分:7)

您可以使用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);
}

但是,实际上,担心效率的时间是工作太慢。

答案 1 :(得分:5)

如果这确实是需要优化的地方,那么你真正应该优化的是以下两件事:

  • 缓冲区分配
  • read()write()
  • 的来电次数

对于100到1000字节的小缓冲区,没有理由使用malloc()之类的东西,只需在堆栈上分配缓冲区,它就会是最快的。当然,除非你想从函数返回指向这些缓冲区的指针,在这种情况下你可能应该使用malloc()。否则,您应该考虑使用全局/静态数组而不是动态分配的数组。

对于I / O调用,请使用整个缓冲区大小调用read()write()。不要让它们读取或写入单个字节。转换到内核和返回确实有成本。

此外,如果您希望在RAM中使用相当大的文件,请考虑使用文件映射。

答案 2 :(得分:4)

stat等。允许您获取文件大小。 http://linux.die.net/man/2/fstat

或者,如果你不能使用它,lseek http://linux.die.net/man/2/lseek(特别注意返回值)

如果你也不能使用它,你可以随时realloc你的缓冲区。

我要由你来实施它,因为这显然是一项任务。 ;)

答案 3 :(得分:2)

在优化任何内容之前,您必须分析您的代码。有许多工具可以做到这一点:

  • 的valgrind
  • 英特尔VTune
  • AQTime
  • AMD CodeAnalyst

答案 4 :(得分:1)

定义一个自动直接扩展的数组。 像这样

#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;
}

答案 5 :(得分:0)

为什么你需要记忆中的一切?你可以有大量的读取,处理,读取下一个块等,
除非你有足够的记忆力,否则你无法将所有记忆保持在你的身上。你的目标是什么?

答案 6 :(得分: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!

brksbrk函数使您可以直接访问malloc使用的同一堆。但没有任何malloc的“开销”。并且没有任何malloc的功能,例如freerealloc。调用sbrk,其大小以字节为单位,并返回void *。使用指针值调用brk(即,您只是想象指针存在并且声明到某个方式),并返回brk

通过使用void *brk分配内存,它使用的mallati将尝试在第一次调用sbrkmalloc时尝试设置和使用相同的空间。许多库函数使用malloc 引擎,因此这个代码有很多方法可以解决。这是一个非常奇怪而有趣的领域。

此处的信号处理程序也非常危险。它为您提供自动无限空间,但当然,如果您遇到任何其他类型的分段违规,例如解除引用NULL指针,处理程序无法修复它,并且它不会再崩溃。所以这可以将程序发送到一个讨厌的循环:重试内存访问,分配更多空间,重试内存访问,分配更多空间。