现在的位置: 首页 > 综合 > 正文

大文件读写——C语言

2013年09月03日 ⁄ 综合 ⁄ 共 6274字 ⁄ 字号 评论关闭

http://blog.chinaunix.net/u1/33412/showart_397173.html

内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。  

  

 

http://hi.baidu.com/ah__fu/blog/item/476799d9313bfeee39012f84.html

 

 

http://hi.baidu.com/ah__fu/blog/item/8fc8132491bb833b8644f9f5.html

 

今天写了一个程序,读一个大文件,报no registers和内存错误信息。后来发现是分配的数组太大了。于是更改了程序,下面程序给出了四种不同方法读写大文件的例子

测试结果表明:最快的是mmap(12 us)、read_bf_once(30143)、read_bf_block(分行读:39106)、malloc(40145)

/*
 * test_rw_binaryfile.c
 *
 *  Created on: Jan 15, 2010
 *      Author: root
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

#define MATRIXSIZE 3601
#define BLOCKSIZE MATRIXSIZE*1

float g_s[MATRIXSIZE][MATRIXSIZE];  //static : this global variable only available in this file. If put it in a function, stack will overflow.

int main(){

int  read_bf_block_malloc(char* file_name);
int  read_bf_block(char* file_name);
int  read_bf_once(char* file_name);
int  read_bf_mmap(char* file_name);
// read_bf_block_malloc("N38W084.bin");
read_bf_block("N38W084.bin");
// read_bf_once("N38W084.bin");
//      read_bf_mmap("N38W084.bin");
// read_bf_mmap("/etc/passwd");
return 0;
}

/*
 *  read_bf_block_malloc(char* file_name) use dynamic allocating memory, not global variant.
 *  It runs slower than others. Maybe, the allocated memory is not consistent comparing others.
 */

int  read_bf_block_malloc(char* file_name){

    FILE * stream = NULL;

    stream = fopen(file_name, "rb" );//b represents binary file

    if (stream == NULL) {
     printf("open file failed");
     return 1;
    }

    if (ftell(stream) != 0) {
     fseek(stream,0,SEEK_SET);
    }

    /****Start: assign dynamic memory with malloc*******/
    float **p_array = NULL;

    int row = MATRIXSIZE;
    int col = MATRIXSIZE;

    struct timeval read_start_time;
    gettimeofday(&read_start_time, NULL);

    p_array = (float **) malloc(row * sizeof(float*));

    if (p_array == NULL) {
     printf("malloc failed!");
    }

    int k;
    for (k=0; k<row; k++) {
     *(p_array+k) = (float *) malloc(col*sizeof(float));
    }
    /****End: assign dynamic memory with malloc*******/

    int count = 0;

    while (feof(stream) == 0) {
     int size = fread(*(p_array+count),sizeof(float),BLOCKSIZE,stream);
     count++;
    }

    struct timeval read_end_time;
    gettimeofday(&read_end_time, NULL);
    printf("Spent time for reading data from disk is %d microseconds\n", read_end_time.tv_usec-read_start_time.tv_usec);

    fclose(stream);

    free(p_array);

    return 0;
}

/*
 * read_bf_block(char* file_name) read data from file in block.
 */

int  read_bf_block(char* file_name)

{

    FILE * stream;

    stream = fopen(file_name, "rb" );//b represents binary file

    if (stream == NULL) {
     printf("open file failed");
     return 1;
    }

    int sum = 0;
    int time = 0;

    if (ftell(stream) != 0) {
     fseek(stream,0,SEEK_SET);
    }

    float *p = g_s;

    struct timeval read_start_time;
    gettimeofday(&read_start_time, NULL);

    while (feof(stream) == 0) {
     int size = fread(p+sum,sizeof(float),BLOCKSIZE,stream);
     sum = ++time * BLOCKSIZE;
    }

    fclose(stream);

    struct timeval read_end_time;
    gettimeofday(&read_end_time, NULL);
    printf("Spent time for reading data from disk is %d microseconds\n", read_end_time.tv_usec-read_start_time.tv_usec);

    return 0;
}

/*
 * readrf:read all the data once.
 */
int  read_bf_once(char* file_name)

{

    FILE * stream;

    stream = fopen(file_name, "rb" );//b represents binary file

//    float s[MATRIXSIZE][MATRIXSIZE]; //It should be set outside of function, otherwise stack will overflow when MATRIXSIZE is large.

    struct timeval read_start_time;
    gettimeofday(&read_start_time, NULL);

    int size = fread(g_s,sizeof(float),MATRIXSIZE*MATRIXSIZE,stream);
//  int size = fread(s,sizeof(float),MATRIXSIZE*MATRIXSIZE,stream);

    if(feof(stream) != 0) {
     printf("error happens reading file\n");
    }
    fclose(stream);

    struct timeval read_end_time;
    gettimeofday(&read_end_time, NULL);
    printf("Spent time for reading data from disk is %d microseconds\n", read_end_time.tv_usec-read_start_time.tv_usec);

    return 0;

}

int  read_bf_mmap(char* file_name)

{

    struct timeval read_start_time;
    gettimeofday(&read_start_time, NULL);

    int fd = open(file_name,O_RDONLY);
    struct stat sb;
    fstat(fd,&sb);
    
    void * start; 
    start = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   
    if (start==MAP_FAILED){
       printf("errors!\n");
       return;
    }
  
//g_s= (float)  start;

//int i=0;
//int j=0;
//for ( i=0; i<MATRIXSIZE; i++) {
// for ( j=0; j<MATRIXSIZE; j++) {
//printf ("s[%d][%d] = %3f/n", i,j,((float *)start)[i*MATRIXSIZE+j]);
//}
//}

    struct timeval read_end_time;
    gettimeofday(&read_end_time, NULL);
    printf("Spent time for reading data from disk is %d microseconds\n", read_end_time.tv_usec-read_start_time.tv_usec);

    munmap(start,sb.st_size);
    close(fd);
}
 

 

原因如下:

定义的二位数组实在是太大了。将大数组的定义移动到函数体外,大功告成!
经过分析,我认为一个函数分配的内存是有限的,在函数体内定义的二维数组太大了,耗尽了堆栈,因此报错。

 

网友总结了下列四法,基本上涵盖全了:

 

方法一:  

  在VC的Project   setting里的link选项卡里把栈开大一点(windows里默认是4M)   
 

方法二:   
  局部变量存放在堆栈中,声明成全局或static的,可以摆脱stack的限制。
全局变量、静态数据、常量存放在全局数据区,所有函数的代码存放在代码区,为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区。   

 

 

1、  静态函数与普通函数的区别在于:静态函数不可以被同一源文件以外的函数调用。

2、  静态局部变量与普通局部变量的区别在于:静态局部变量只初始化一次,下一次初始化实际上是依然是上一次的变量;

3、  静态全局变量与普通全局变量的区别在于:静态全局变量的作用域仅限于所在的源文件。

 

 在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
    栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
    堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
    自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
    全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的(初始化的全局变量和静态变量在一块区域,未初始化的全局变量与静态变量在相邻的另一块区域,同时未被初始化的对象存储区可以通过void*来访问和操纵,程序结束后由系统自行释放),在C++里面没有这个区分了,他们共同占用同一块内存区。
    常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)
文章出处:DIY部落(http://www.diybl.com/course/3_program/c++/cppjs/20091112/182134.html) ,该文还有一些更详细的关于几种存储方式优劣的比较。

 

 

 

 

 

方法三:   

  int     Array[90000];       //   分配栈空间  

  int     *pArray   =   new   int[90000];       //   分配堆空间   
  delete pArray;

  堆要比栈大得多~用后者   
 

方法四:  

  用vector  
  #include   <vector>  
   
  using   namespace   std;  
   
  void   main()  
  {  
        vector<int>   A(90000);  
        A[0]   =   1;  
  }

 

  可以用new   或vector在堆中申请  
  new   是你自己来管理内存,而vector   是自动管理  
  尽量用vector   ,出错的机会小的多   
  但如果对内存管理还有特殊要求的话,还是自己来管理好

 

 

http://www.blogjava.net/windonly/archive/2009/06/16/282602.html

 

最近需要用C操作文件,但是使用fopen和fseek的时候,在32位操作系统中,没办法操作2G以上的文件,后面经过多次Google和高手指点之后通过open64、lseek解决这个问题:

抱歉!评论已关闭.