1. 程式人生 > >C++快速文件輸入輸出

C++快速文件輸入輸出

方式 byte closed ++ 關閉 高端 inline eof 文件輸入

轉載請註明:

仰望高端玩家的小清新 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 }

C++快速文件輸入輸出