转载请注明:

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

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

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

 #include <cstdio> // EOF 的定义
#include <cassert> // assert 函数定义
#include <sys/stat.h> // 读取文件状态 /**
* 快速输入输出模板
* 使用 fread 和 fwrite 获得高于 scanf 和 printf 的文件 I/O 性能
*/
namespace FastIO { // 快速输入
namespace in{
const int inputBuffSize = ; // 输入缓冲区大小 64MB
char buff[inputBuffSize], *ptr = NULL, *pend = NULL;
FILE *stream = NULL;
int filesize, readsize, itemsize, maxcnt, maxbytes; // 文件大小字节数, 已读字节数 // 指定文件路径, 并根据文件头获取文件大小
inline int getsize(const char *path){
struct stat statbuff;
stat(path, &statbuff);
return statbuff.st_size;
} /* 初始化 Fast in 参数
* (const char*) path: 文件路径
* (const char*) mode: 文件打开模式
* (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
*/
inline void init(const char *path, const char *mode="rb", const int element_size=){
assert((stream == NULL) && (stream = fopen(path, mode)) != NULL);
filesize = getsize(path);
readsize = ;
itemsize = element_size;
maxcnt = inputBuffSize / element_size; // buffer 整块读取时可容纳的最大块数
maxbytes = (inputBuffSize / element_size) * element_size; // buffer 整块读取时可容纳的最大字节数
ptr = pend = NULL;
} /**
* 读取流 stream 中的下一个字符, 当缓冲区内容读取完毕后进行下一次I/O
* 返回EOF(-1)表示读取完成, 返回-2表示达到文件尾之前出错
*/
inline char nextchar(){
if (readsize >= filesize) return EOF; // 文件读取完成
if (ptr >= pend){
int realbytes = itemsize * fread(buff, itemsize, maxcnt, stream); // fread返回实际读取的块数
if (realbytes < maxbytes && realbytes + readsize < filesize) return -; // 读取出错 返回-2
ptr = buff; // 重置首尾指针
pend = buff + realbytes;
}
return readsize++, *ptr++;
} // 读取一个整数, true 表示读取成功, false 表示读取失败
inline bool read(int &x){
char c = nextchar();
while (c >= && c != '-' && (c < '' || c > '')) c = nextchar();
if (c < ) return false; // c == -1 (EOF): 到达文件尾, c == -2: 读取出错
int sign = (c == '-') ? - : ; // 正负号
x = (c == '-') ? : c - '';
while (c = nextchar(), c >= '' && c <= '') x = x * + c - '';
x *= sign;
return true;
} // 读取一个长度为 n 的整数 tuple, 如 (1, -2, 31), true 表示读取成功, false 表示失败
inline bool read(int *p, const int n){
for (int *end = p + n; p < end; ++p) if (!read(*p)) return false;
return true;
} // 关闭输入流释放资源
inline int close(){
int ret = fclose(stream);
filesize = readsize = itemsize = maxcnt = ;
ptr = pend = NULL;
stream = NULL;
return ret;
}
} // 快速输出
namespace out{
const int outputBuffSize = ; // 输出缓冲区大小 64MB
char buff[outputBuffSize], *ptr = NULL, *pend = NULL;
FILE *stream = NULL;
int itemsize, maxbytes; // 写入的块大小, 整块存放时缓存的最大字节数 inline void init(const char *path, const char *mode="wb", const int element_size=){
assert(stream == NULL && (stream = fopen(path, mode)) != NULL);
itemsize = element_size;
maxbytes = (outputBuffSize / element_size) * element_size; // 输出缓冲的最大字节数
ptr = buff;
pend = buff + maxbytes;
} // 冲刷缓冲区
inline void flush(){
fwrite(buff, itemsize, (ptr - buff) / itemsize, stream);
ptr = buff; // 调整首指针
fflush(stream);
} // 写入一个字符到文件中
inline void write(const char &c){
if (ptr >= pend) flush();
*ptr++ = c;
} // 写一个字符串到文件中
inline void write(const char *s){
for(; *s; ++s) write(*s); // 读取到字符串尾部时 '\0' ASCII为0
} // 写入一个整数到文件中
inline void write(int x){
char buf[], *p = buf;
if (x == ) write('');
if (x < ) write('-'), x = -x;
while (x > ) *p++ = x % + '', x /= ;
while (p > buf) write(*--p);
} // 写入一个整型tuple到文件中 如 (32, -1, 14), drop_end 控制是否输出 end 符号
inline void write(const int *p, const int n, const char *left="(", const char *right=")",
const char *split=", ", const char *end="\n", const bool drop_end=false){
write(left);
for (const int *ptrend = p + n - ; p < ptrend; ++p){
write(*p);
write(split);
}
write(*++p);
write(right);
if (!drop_end) write(end);
} // 冲刷缓冲并关闭输出流释放资源
inline int close(){
if (ptr > buff) flush();
int ret = fclose(stream);
ptr = pend = NULL;
stream = NULL;
return ret;
}
}
}

FastIO.cpp

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

 #pragma once
#include <cstdio> // EOF 的定义
#include <string> // string 类型的支持
#include <cassert> // assert 函数定义
#include <sys/stat.h> // 读取文件状态
#include <vector> // 读写vector #define inputBuffSize (67108864) // 输入缓冲区大小 64MB
#define outputBuffSize (67108864) // 输入缓冲区大小 64MB namespace FastIO { // 由于头文件中可以定义内联函数, 因此将FastIO定义在头文件中便于使用
// 快速输入
namespace in{
char buff[inputBuffSize], *ptr = NULL, *pend = NULL;
FILE *stream = NULL;
int filesize, readsize, itemsize, maxcnt, maxbytes; // 文件大小字节数, 已读字节数 // 指定文件路径, 并根据文件头获取文件大小
inline int getsize(const char *path){
struct stat statbuff;
stat(path, &statbuff);
return statbuff.st_size;
} // 初始化 Fast in 参数
// (const char*) path: 文件路径
// (const char*) mode: 文件打开模式
// (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
inline void init(const char *path, const char *mode="rb", const int element_size=){
assert((stream == NULL) && (stream = fopen(path, mode)) != NULL);
filesize = getsize(path);
readsize = ;
itemsize = element_size;
maxcnt = inputBuffSize / element_size; // buffer 整块读取时可容纳的最大块数
maxbytes = (inputBuffSize / element_size) * element_size; // buffer 整块读取时可容纳的最大字节数
ptr = pend = NULL;
} // 初始化 Fast in 参数
// (const string) path: 文件路径
// (const char*) mode: 文件打开模式
// (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
inline void init(const std::string &path, const char *mode="rb", const int element_size=){
init(path.c_str(), mode, element_size);
} // 读取流 stream 中的下一个字符, 当缓冲区内容读取完毕后进行下一次I/O
// 返回EOF(-1)表示读取完成, 返回-2表示达到文件尾之前出错
inline char nextchar(){
if (readsize >= filesize) return EOF; // 文件读取完成
if (ptr >= pend){
int realbytes = itemsize * fread(buff, itemsize, maxcnt, stream); // fread返回实际读取的块数
if (realbytes < maxbytes && realbytes + readsize < filesize) return -; // 读取出错 返回-2
ptr = buff; // 重置首尾指针
pend = buff + realbytes;
}
return readsize++, *ptr++;
} // 读取一个字符, 读取失败则不改变char, 否则改变char c的值
inline bool read(char &c){
char tmp = nextchar(); // tmp == -1 (EOF): 到达文件尾, tmp == -2: 读取出错
return tmp < ? false : (c = tmp, true);
} // 读取一个整数, true 表示读取成功, false 表示读取失败
inline bool read(int &x){
char c = nextchar();
while (c >= && c != '-' && (c < '' || c > '')) c = nextchar();
if (c < ) return false; // c == -1 (EOF): 到达文件尾, c == -2: 读取出错
int sign = (c == '-') ? - : ; // 正负号
x = (c == '-') ? : c - '';
while (c = nextchar(), c >= '' && c <= '') x = x * + c - '';
x *= sign;
return true;
} // 读取一个长度为 n 的整数 tuple, 如 (1, -2, 31), true 表示读取成功, false 表示失败
inline bool read(int *p, const int n){
for (int *end = p + n; p < end; ++p) if (!read(*p)) return false;
return true;
} // 关闭输入流释放资源
inline int close(){
int ret = fclose(stream);
filesize = readsize = itemsize = maxcnt = ;
ptr = pend = NULL;
stream = NULL;
return ret;
}
} // 快速输出
namespace out{
char buff[outputBuffSize], *ptr = NULL, *pend = NULL;
FILE *stream = NULL;
int itemsize, maxbytes; // 写入的块大小, 整块存放时缓存的最大字节数 // 初始化 Fast out 参数
// (const char*) path: 文件路径
// (const char*) mode: 文件打开模式
// (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
inline void init(const char *path, const char *mode="wb", const int element_size=){
assert(stream == NULL && (stream = fopen(path, mode)) != NULL);
itemsize = element_size;
maxbytes = (outputBuffSize / element_size) * element_size; // 输出缓冲的最大字节数
ptr = buff;
pend = buff + maxbytes;
} // 初始化 Fast out 参数
// (const string) path: 文件路径
// (const char*) mode: 文件打开模式
// (const int) element_size=1: 文件读取的块大小, 默认为 1 字节, 缓冲区大小为 64M
inline void init(const std::string &path, const char *mode="wb", const int element_size=){
init(path.c_str(), mode, element_size);
} // 冲刷缓冲区
inline void flush(){
fwrite(buff, itemsize, (ptr - buff) / itemsize, stream);
ptr = buff; // 调整首指针
fflush(stream);
} // 写入一个字符到文件中
inline void write(const char &c){
if (ptr >= pend) flush();
*ptr++ = c;
} // 写一个字符串到文件中
inline void write(const char *s){
for(; *s; ++s) write(*s); // 读取到字符串尾部时 '\0' ASCII为0
} // 写一个 string 类型的字符串到文件中
inline void write(const std::string &s){
write(s.c_str());
} // 写入一个整数到文件中
inline void write(int x){
char buf[], *p = buf;
if (x == ) write('');
if (x < ) write('-'), x = -x;
while (x > ) *p++ = x % + '', x /= ;
while (p > buf) write(*--p);
} template<typename T>
// 写入一个含有n个元素的tuple到文件中 如 (32, -1, 14), drop_end 控制是否输出 end 符号
inline void write(const T *p, int n, const char *left="(", const char *right=")",
const char *split=", ", const char *end="\n", const bool drop_end=false){
write(left);
while (--n) write(*p++), write(split);
write(*p);
write(right);
if (!drop_end) write(end);
} template<typename T>
// 写入一个使用 vector 存储的 tuple
inline void write(std::vector<T> &vec, const char *left="(", const char *right=")",
const char *split=", ", const char *end="\n", const bool drop_end=false){
int n = vec.size() - ;
write(left);
for (int i = ; i < n; ++i) write(vec[i]), write(split);
write(vec[n]);
write(right);
if (!drop_end) write(end);
} // 冲刷缓冲并关闭输出流释放资源
inline int close(){
if (ptr > buff) flush();
int ret = fclose(stream);
ptr = pend = NULL;
stream = NULL;
return ret;
}
}
}

FastIO.h

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

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

 // 在 main.cpp 中引入FastIO.h 和 命名空间 FastIO 即可

 #include"FastIO.h"
using namespace FastIO; int main(int argc, char *argv[]){
int buff[];
// 初始化写入文件流
out::init("out.txt", "wb");
// 测试5个数一组的tuple读取和写入
in::init("in.txt", "rb");
while(in::read(buff, )) out::write(buff, );
// 释放读文件资源
in::close();
// 释放写文件资源,冲刷缓冲区
out::close();
}

C++快速文件输入输出的更多相关文章

  1. [软件推荐]快速文件复制工具(Limit Copy) V4.0 绿色版

    快速文件复制工具(Limit Copy)绿色版是一款智能变频超快复制绿色软件. 快速文件复制工具(Limit Copy)功能比较完善,除了文件复制还可以智能变频,直接把要复制的文件拖入窗口即可,无需手 ...

  2. C++IO类&文件输入输出

    C++IO类&文件输入输出 istream(输入流)类型,提供输入操作. ostream(输出流)类型,提供输出操作. cin,一个istream对象,从标准输入读取数据. cout,一个os ...

  3. Java通过NIO实现快速文件拷贝的代码

    将内容过程重要的内容片段做个记录,下面的内容段是关于Java通过NIO实现快速文件拷贝的内容. public static void fileCopy( File in, File out ) thr ...

  4. python 中文件输入输出及os模块对文件系统的操作

    整理了一下python 中文件的输入输出及主要介绍一些os模块中对文件系统的操作. 文件输入输出 1.内建函数open(file_name,文件打开模式,通用换行符支持),打开文件返回文件对象. 2. ...

  5. IO库----IO类,文件输入输出,string流

    一.IO类 1.IO库类型和头文件表: 头文件 类型 iostream istream,wistream 从流读取数据 ostream,wostream 向流写入数据 iostream,wiostre ...

  6. 第五次程序设计作业 C++计算器雏形 调用文件输入输出

    一.C++计算器作业系列链接 第三次作业:C++计算器雏形 第三次作业附加:代码规范 第四次作业:命令行的调用及计算 MyGithub 二.本次作业相关 要求:第五次程序设计作业 根据这一次的作业要求 ...

  7. 文件输入输出实例&Ptask的编写

    前言 最近在写Ptask,顺便了解了如何进行文件读入输出.而在Ptask中最重要,也是最最容易出bug的地方就是文件操作.那么如何进行文件输入输出,在程序中起到重要作用呢? 输入 首先为了保证可以在控 ...

  8. freopen - C/C++文件输入输出利器

    freopen以前经常使用,比较方便,可以当作模板,在中间替换为自己的代码即可使用. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h&g ...

  9. 文件输入输出C++操作

    基于C++的文件操作 在C++中,有一个stream这个类,所有的I/O都以这个"流"类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符: 1.插入器(& ...

随机推荐

  1. 数据分析与展示---Numpy入门

    概括: 一:数据维度 (一)一维数据 (二)二维数据 (三)多维数据 (四)高维数据 二:Numpy的数组对象:ndarray (一)Numpy介绍 (二)N维数组对象ndarray (三)ndarr ...

  2. 给APP增加RSA签名

    RSA签名,Google主要用于APP的来源控制与结算.所谓的结算,也是就是控制了APP只有使用现在机子上登录的Google账户从Google市场曾经下载过该APP的才能够使用,这样也就达到了app销 ...

  3. Disruptor的使用

    ..................2015年的第一天................... 本文代码托管在 https://github.com/hupengcool/disruptor-start ...

  4. 面试整理(3)js事件委托

    事件委托主要用于一个父容器下面有很多功能相仿的子容器,这时候就需要将子容器的事件监听交给父容器来做.父容器之所以能够帮子容器监听其原理是事件冒泡,对于子容器的点击在冒泡时会被父容器捕获到,然后用e.t ...

  5. 【leetcode 简单】第三题 回文数

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...

  6. typeof运算符

    javascript中typeof用来判断一个变量或表达式的数据类型. typeof 返回值有六种可能: "number," "string," "b ...

  7. C++类型转换 -- 由其他类型转换到自定义类型

    由其他类型转换到自定义类型 由其他类型(如int,double)向自定义类的转换是由构造函数来实现,只有当类的定义和实现中提供了合适的构造函数,转换才能通过. /******************* ...

  8. imperva系统升级遇见的错误(配置文件的导入导出)

    今天心态有点炸了 今天去东兴证券做waf升级.浪费了两天才弄完.把客户都弄得有点急了.好歹原厂的工程师耐心的讲解这才弄完.感谢路哥.... 赶紧总结一下. 事情是这样的.东兴 证券的imperva是v ...

  9. Postgres中tuple的组装与插入

    1.相关的数据类型 我们先看相关的数据类型: HeapTupleData(src/include/access/htup.h) typedef struct HeapTupleData { uint3 ...

  10. MySQL源码分析(一)

    近段时间简单看了下Mysql源码相关内容,主要从一个select查询出发,查看了一下整个代码结构.分析总结如下: https://mubu.com/doc/explore/13965