转载请注明:

仰望高端玩家的小清新 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. 数据分析与展示---anaconda的使用

    一:安装 官方源:https://repo.continuum.io/archive/(太慢) 清华源:https://mirrors.tuna.tsinghua.edu.cn/anaconda/ar ...

  2. 基础知识:BT1120

    今天谈点我所理解的BT1120协议. BT1120是高清晰度电视 (HDTV) 演播室信号数字接口,首先说一下接口标准里面的概念,然后谈谈自己的理解,写这个文章的目的就是解释给自己听的,所以都是一些白 ...

  3. JS数组---转及补充--

    javascript之数组操作 1.数组的创建 var arr=Array();//写的角标数及直接写角标对应的内容简写 var arr=Array("我","爱&quo ...

  4. 【算法日记】Dijkstra最短路径算法

    上一篇再说广度优先搜索的适合提到了图. 狄克斯拉特算法是在图的基础上增加了 加权图的概念.就是节点和节点之间是有不同距离的 1.算法实例 用Dijkstra算法找出以A为起点的单源最短路径步骤如下 算 ...

  5. Java实现链式存储的二叉树

    二叉树的定义: 二叉树(BinaryTree)是n(n≥0)个结点的有限集,它或者是空集(n=0),或者由一个根结点及两棵互不相交的.分别称作这个根的左子树和右子树的二叉树组成. 二叉树的遍历方式主要 ...

  6. laravel artisan 工具心得

    介绍一些非常好用的命令: 1.创建一个Eloquent模型:顺便创建一个对应的数据库表 php artisan make:model --migration Models/Admin/test 2.将 ...

  7. Sublime text 3中文汉化教程

    想弄个中文版的sublime,居然可以不用重新下载汉化包或者重新下载简体中文版了~而是只需要安装个插件即可!   工具/原料   电脑 sublime text3编辑器 方法/步骤    启动并进入s ...

  8. Java Spring boot 企业微信点餐系统

    欢迎关注我的微信公众号:"Java面试通关手册" 回复关键字" springboot "免费领取(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美 ...

  9. Mysql储存过程2:变量定义与参数传递

    #储存过程 中的变量定义 declare 变量名 类型 可选类型 -- 跟建表差不多 create procedure p() begin ); ; select age+number; end$ / ...

  10. 78.PL和PS通过BRAM交互共享数据

    本篇文章目的是使用Block Memory进行PS和PL的数据交互或者数据共享,通过zynq PS端的Master GP0端口向BRAM写数据,然后再通过PS端的Mater GP1把数据读出来,将结果 ...