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); // 讀取到字符串尾部時 '\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 <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); // 讀取到字符串尾部時 '\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<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="\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<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="\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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM