zoukankan      html  css  js  c++  java
  • C++快速文件输入输出

    转载请注明:

    仰望高端玩家的小清新 http://www.cnblogs.com/luruiyuan/

    C语言可以获得接近汇编的性能,而输入输出常常是最为耗时的过程,因此可以使用 C 语言中的 fread 和 fwrite 来获得最高的读写性能。

    例如,可以将其写在源码文件中直接使用:不建议使用这种方式,并且FastIO.cpp代码中有几个bug,懒得改了。直接用FastIO.h即可,这里的改过bug了。

      1 #include <cstdio> // EOF 的定义
      2 #include <cassert> // assert 函数定义
      3 #include <sys/stat.h> // 读取文件状态
      4 
      5 /**
      6  * 快速输入输出模板 
      7  * 使用 fread 和 fwrite 获得高于 scanf 和 printf 的文件 I/O 性能
      8  */
      9 namespace FastIO {
     10 
     11     // 快速输入
     12     namespace in{
     13         const int inputBuffSize = 67108864; // 输入缓冲区大小 64MB
     14         char buff[inputBuffSize], *ptr = NULL, *pend = NULL;
     15         FILE *stream = NULL;
     16         int filesize, readsize, itemsize, maxcnt, maxbytes; // 文件大小字节数, 已读字节数
     17 
     18         // 指定文件路径, 并根据文件头获取文件大小
     19         inline int getsize(const char *path){
     20             struct stat statbuff;
     21             stat(path, &statbuff);
     22             return statbuff.st_size;
     23         }
     24 
     25         /* 初始化 Fast in 参数
     26          *      (const char*) path: 文件路径
     27          *      (const char*) mode: 文件打开模式
     28          *   (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
     29          */
     30         inline void init(const char *path, const char *mode="rb", const int element_size=1){
     31             assert((stream == NULL) && (stream = fopen(path, mode)) != NULL);
     32             filesize = getsize(path);
     33             readsize = 0;
     34             itemsize = element_size;
     35             maxcnt = inputBuffSize / element_size; // buffer 整块读取时可容纳的最大块数
     36             maxbytes = (inputBuffSize / element_size) * element_size; // buffer 整块读取时可容纳的最大字节数
     37             ptr = pend = NULL;
     38         }
     39 
     40         /**
     41          * 读取流 stream 中的下一个字符, 当缓冲区内容读取完毕后进行下一次I/O
     42          * 返回EOF(-1)表示读取完成, 返回-2表示达到文件尾之前出错
     43          */
     44         inline char nextchar(){
     45             if (readsize >= filesize) return EOF; // 文件读取完成
     46             if (ptr >= pend){
     47                 int realbytes = itemsize * fread(buff, itemsize, maxcnt, stream); // fread返回实际读取的块数
     48                 if (realbytes < maxbytes && realbytes + readsize < filesize) return -2; // 读取出错 返回-2
     49                 ptr = buff; // 重置首尾指针
     50                 pend = buff + realbytes;
     51             }
     52             return readsize++, *ptr++;
     53         }
     54 
     55         // 读取一个整数, true 表示读取成功, false 表示读取失败
     56         inline bool read(int &x){
     57             char c = nextchar();
     58             while (c >= 0 && c != '-' && (c < '0' || c > '9')) c = nextchar();
     59             if (c < 0) return false; // c == -1 (EOF): 到达文件尾, c == -2: 读取出错
     60             int sign = (c == '-') ? -1 : 1; // 正负号
     61             x = (c == '-') ? 0 : c - '0';
     62             while (c = nextchar(), c >= '0' && c <= '9') x = x * 10 + c - '0';
     63             x *= sign;
     64             return true;
     65         }
     66 
     67         // 读取一个长度为 n 的整数 tuple, 如 (1, -2, 31), true 表示读取成功, false 表示失败
     68         inline bool read(int *p, const int n){
     69             for (int *end = p + n; p < end; ++p) if (!read(*p)) return false;
     70             return true;
     71         }
     72 
     73         // 关闭输入流释放资源
     74         inline int close(){
     75             int ret = fclose(stream);
     76             filesize = readsize = itemsize = maxcnt = 0;
     77             ptr = pend = NULL;
     78             stream = NULL;
     79             return ret;
     80         }
     81     }
     82 
     83     // 快速输出
     84     namespace out{
     85         const int outputBuffSize = 67108864; // 输出缓冲区大小 64MB
     86         char buff[outputBuffSize], *ptr = NULL, *pend = NULL;
     87         FILE *stream = NULL;
     88         int itemsize, maxbytes; // 写入的块大小, 整块存放时缓存的最大字节数
     89 
     90         inline void init(const char *path, const char *mode="wb", const int element_size=1){
     91             assert(stream == NULL && (stream = fopen(path, mode)) != NULL);
     92             itemsize = element_size;
     93             maxbytes = (outputBuffSize / element_size) * element_size; // 输出缓冲的最大字节数
     94             ptr = buff;
     95             pend = buff + maxbytes;
     96         }
     97 
     98         // 冲刷缓冲区
     99         inline void flush(){
    100             fwrite(buff, itemsize, (ptr - buff) / itemsize, stream);
    101             ptr = buff; // 调整首指针
    102             fflush(stream);
    103         }
    104 
    105         // 写入一个字符到文件中
    106         inline void write(const char &c){
    107             if (ptr >= pend) flush();
    108             *ptr++ = c;
    109         }
    110 
    111         // 写一个字符串到文件中
    112         inline void write(const char *s){
    113             for(; *s; ++s) write(*s); // 读取到字符串尾部时 '' ASCII为0
    114         }
    115 
    116         // 写入一个整数到文件中
    117         inline void write(int x){
    118             char buf[20], *p = buf;
    119             if (x == 0) write('0');
    120             if (x < 0) write('-'), x = -x;
    121             while (x > 0) *p++ = x % 10 + '0', x /= 10;
    122             while (p > buf) write(*--p);
    123         }
    124 
    125         // 写入一个整型tuple到文件中 如 (32, -1, 14), drop_end 控制是否输出 end 符号
    126         inline void write(const int *p, const int n, const char *left="(", const char *right=")",
    127                           const char *split=", ", const char *end="
    ", const bool drop_end=false){
    128             write(left);
    129             for (const int *ptrend = p + n - 1; p < ptrend; ++p){
    130                 write(*p);
    131                 write(split);
    132             }
    133             write(*++p);
    134             write(right);
    135             if (!drop_end) write(end);
    136         }
    137 
    138         // 冲刷缓冲并关闭输出流释放资源
    139         inline int close(){
    140             if (ptr > buff) flush();
    141             int ret = fclose(stream);
    142             ptr = pend = NULL;
    143             stream = NULL;
    144             return ret;
    145         }
    146     }
    147 }
    FastIO.cpp

    由于内联函数可以写入到头文件中,因此可以将FastIO的实现放入 FastIO.h 中,然后在调用时通过 include 包含即可,FastIO.h 如下,其中包含了对于string类型的支持:强烈建议使用这种方式 

      1 #pragma once
      2 #include <cstdio> // EOF 的定义
      3 #include <string> // string 类型的支持
      4 #include <cassert> // assert 函数定义
      5 #include <sys/stat.h> // 读取文件状态
      6 #include <vector> // 读写vector
      7 
      8 #define inputBuffSize (67108864) // 输入缓冲区大小 64MB
      9 #define outputBuffSize (67108864) // 输入缓冲区大小 64MB
     10 
     11 namespace FastIO { // 由于头文件中可以定义内联函数, 因此将FastIO定义在头文件中便于使用
     12     // 快速输入
     13     namespace in{
     14         char buff[inputBuffSize], *ptr = NULL, *pend = NULL;
     15         FILE *stream = NULL;
     16         int filesize, readsize, itemsize, maxcnt, maxbytes; // 文件大小字节数, 已读字节数
     17 
     18         // 指定文件路径, 并根据文件头获取文件大小
     19         inline int getsize(const char *path){
     20             struct stat statbuff;
     21             stat(path, &statbuff);
     22             return statbuff.st_size;
     23         }
     24 
     25         // 初始化 Fast in 参数
     26         //      (const char*) path: 文件路径
     27         //      (const char*) mode: 文件打开模式
     28         //   (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
     29         inline void init(const char *path, const char *mode="rb", const int element_size=1){
     30             assert((stream == NULL) && (stream = fopen(path, mode)) != NULL);
     31             filesize = getsize(path);
     32             readsize = 0;
     33             itemsize = element_size;
     34             maxcnt = inputBuffSize / element_size; // buffer 整块读取时可容纳的最大块数
     35             maxbytes = (inputBuffSize / element_size) * element_size; // buffer 整块读取时可容纳的最大字节数
     36             ptr = pend = NULL;
     37         }
     38 
     39         // 初始化 Fast in 参数
     40         //      (const string) path: 文件路径
     41         //      (const char*) mode: 文件打开模式
     42         //   (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
     43         inline void init(const std::string &path, const char *mode="rb", const int element_size=1){
     44             init(path.c_str(), mode, element_size);
     45         }
     46 
     47         // 读取流 stream 中的下一个字符, 当缓冲区内容读取完毕后进行下一次I/O
     48         // 返回EOF(-1)表示读取完成, 返回-2表示达到文件尾之前出错
     49         inline char nextchar(){
     50             if (readsize >= filesize) return EOF; // 文件读取完成
     51             if (ptr >= pend){
     52                 int realbytes = itemsize * fread(buff, itemsize, maxcnt, stream); // fread返回实际读取的块数
     53                 if (realbytes < maxbytes && realbytes + readsize < filesize) return -2; // 读取出错 返回-2
     54                 ptr = buff; // 重置首尾指针
     55                 pend = buff + realbytes;
     56             }
     57             return readsize++, *ptr++;
     58         }
     59 
     60         // 读取一个字符, 读取失败则不改变char, 否则改变char c的值
     61         inline bool read(char &c){
     62             char tmp = nextchar(); // tmp == -1 (EOF): 到达文件尾, tmp == -2: 读取出错
     63             return tmp < 0 ? false : (c = tmp, true);
     64         }
     65 
     66         // 读取一个整数, true 表示读取成功, false 表示读取失败
     67         inline bool read(int &x){
     68             char c = nextchar();
     69             while (c >= 0 && c != '-' && (c < '0' || c > '9')) c = nextchar();
     70             if (c < 0) return false; // c == -1 (EOF): 到达文件尾, c == -2: 读取出错
     71             int sign = (c == '-') ? -1 : 1; // 正负号
     72             x = (c == '-') ? 0 : c - '0';
     73             while (c = nextchar(), c >= '0' && c <= '9') x = x * 10 + c - '0';
     74             x *= sign;
     75             return true;
     76         }
     77 
     78         // 读取一个长度为 n 的整数 tuple, 如 (1, -2, 31), true 表示读取成功, false 表示失败
     79         inline bool read(int *p, const int n){
     80             for (int *end = p + n; p < end; ++p) if (!read(*p)) return false;
     81             return true;
     82         }
     83 
     84         // 关闭输入流释放资源
     85         inline int close(){
     86             int ret = fclose(stream);
     87             filesize = readsize = itemsize = maxcnt = 0;
     88             ptr = pend = NULL;
     89             stream = NULL;
     90             return ret;
     91         }
     92     }
     93 
     94     // 快速输出
     95     namespace out{
     96         char buff[outputBuffSize], *ptr = NULL, *pend = NULL;
     97         FILE *stream = NULL;
     98         int itemsize, maxbytes; // 写入的块大小, 整块存放时缓存的最大字节数
     99 
    100         // 初始化 Fast out 参数
    101         //      (const char*) path: 文件路径
    102         //      (const char*) mode: 文件打开模式
    103         //   (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
    104         inline void init(const char *path, const char *mode="wb", const int element_size=1){
    105             assert(stream == NULL && (stream = fopen(path, mode)) != NULL);
    106             itemsize = element_size;
    107             maxbytes = (outputBuffSize / element_size) * element_size; // 输出缓冲的最大字节数
    108             ptr = buff;
    109             pend = buff + maxbytes;
    110         }
    111 
    112         // 初始化 Fast out 参数
    113         //      (const string) path: 文件路径
    114         //      (const char*) mode: 文件打开模式
    115         //   (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
    116         inline void init(const std::string &path, const char *mode="wb", const int element_size=1){
    117             init(path.c_str(), mode, element_size);
    118         }
    119 
    120         // 冲刷缓冲区
    121         inline void flush(){
    122             fwrite(buff, itemsize, (ptr - buff) / itemsize, stream);
    123             ptr = buff; // 调整首指针
    124             fflush(stream);
    125         }
    126 
    127         // 写入一个字符到文件中
    128         inline void write(const char &c){
    129             if (ptr >= pend) flush();
    130             *ptr++ = c;
    131         }
    132 
    133         // 写一个字符串到文件中
    134         inline void write(const char *s){
    135             for(; *s; ++s) write(*s); // 读取到字符串尾部时 '' ASCII为0
    136         }
    137 
    138         // 写一个 string 类型的字符串到文件中
    139         inline void write(const std::string &s){
    140             write(s.c_str());
    141         }
    142 
    143         // 写入一个整数到文件中
    144         inline void write(int x){
    145             char buf[20], *p = buf;
    146             if (x == 0) write('0');
    147             if (x < 0) write('-'), x = -x;
    148             while (x > 0) *p++ = x % 10 + '0', x /= 10;
    149             while (p > buf) write(*--p);
    150         }
    151 
    152         template<typename T>
    153         // 写入一个含有n个元素的tuple到文件中 如 (32, -1, 14), drop_end 控制是否输出 end 符号
    154         inline void write(const T *p, int n, const char *left="(", const char *right=")",
    155                           const char *split=", ", const char *end="
    ", const bool drop_end=false){
    156             write(left);
    157             while (--n) write(*p++), write(split);
    158             write(*p);
    159             write(right);
    160             if (!drop_end) write(end);
    161         }
    162 
    163         template<typename T>
    164         // 写入一个使用 vector 存储的 tuple
    165         inline void write(std::vector<T> &vec, const char *left="(", const char *right=")",
    166                           const char *split=", ", const char *end="
    ", const bool drop_end=false){
    167             int n = vec.size() - 1;
    168             write(left);
    169             for (int i = 0; i < n; ++i) write(vec[i]), write(split);
    170             write(vec[n]);
    171             write(right);
    172             if (!drop_end) write(end);
    173         }
    174 
    175         // 冲刷缓冲并关闭输出流释放资源
    176         inline int close(){
    177             if (ptr > buff) flush();
    178             int ret = fclose(stream);
    179             ptr = pend = NULL;
    180             stream = NULL;
    181             return ret;
    182         }
    183     }
    184 }
    FastIO.h

    调用时,只需将头文件 FastIO.h 引入,然后使用其命名空间 FastIO::in, FastIO::out

    简单的使用方式如下,这里假定了 main.cpp 和 FastIO.h 在同一个目录下:(如果不在,需要用相对路径)

     1 // 在 main.cpp 中引入FastIO.h 和 命名空间 FastIO 即可
     2 
     3 #include"FastIO.h"
     4 using namespace FastIO;
     5 
     6 int main(int argc, char *argv[]){
     7     int buff[10];
     8     // 初始化写入文件流
     9     out::init("out.txt", "wb");
    10     // 测试5个数一组的tuple读取和写入 
    11     in::init("in.txt", "rb");
    12     while(in::read(buff, 5)) out::write(buff, 5);
    13     // 释放读文件资源
    14     in::close();
    15     // 释放写文件资源,冲刷缓冲区
    16     out::close();
    17 }
  • 相关阅读:
    爬虫必备—性能相关(异步非阻塞)
    JPA自定义查询@Query分页
    iiview Select 选择框打勾选中的内容label和展示的不一致
    ivew Table 固定列设置后,底部拖拽的横轴被覆盖拉不动
    vue消息提示Message
    LeafLet之气泡框隐藏"x"图标
    vue 之 折线图挤压
    iView之清空选择框
    iview之select选择框选中内容后有空格的问题
    iview组件select之默认展示label,并传空value做方法入参
  • 原文地址:https://www.cnblogs.com/luruiyuan/p/10518374.html
Copyright © 2011-2022 走看看