C++快速文件输入输出

转载请注明:

 

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

 

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

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

  1 #include  // EOF 的定义
  2 #include  // assert 函数定义
  3 #include  // 读取文件状态
  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 如下,其中包含了对于string类型的支持:强烈建议使用这种方式 

 

  1 #pragma once
  2 #include  // EOF 的定义
  3 #include <string> // string 类型的支持
  4 #include  // assert 函数定义
  5 #include  // 读取文件状态
  6 #include  // 读写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); // 读取到字符串尾部时 '\0' 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
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="\n", 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
164         // 写入一个使用 vector 存储的 tuple
165         inline void write(std::vector &vec, const char *left="(", const char *right=")",
166                           const char *split=", ", const char *end="\n", 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 }

 

转载于:https://www.cnblogs.com/luruiyuan/p/10518374.html

你可能感兴趣的:(C++快速文件输入输出)