C++快速文件输入输出

时间:2019-03-13 17:40:30   收藏:0   阅读:225

转载请注明:

 

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

 

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

例如,可以将其写在源码文件中直接使用:

技术分享图片
  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); // 读取到字符串尾部时 ‘\0‘ 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="\n", 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 如下:

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

 

原文:https://www.cnblogs.com/luruiyuan/p/10518374.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!