转载请注明:

仰望高端玩家的小清新 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. vue 一开始

    项目安装 vue init webpack bibivue-router Y npm run dev

  2. kvm虚拟机

    ###查看虚拟机的状态 [root@fgeserver2 ~]# virsh list --all Id Name State------------------------------------- ...

  3. Image Scaling using Deep Convolutional Neural Networks

    Image Scaling using Deep Convolutional Neural Networks This past summer I interned at Flipboard in P ...

  4. JAVA多线程提高十二:阻塞队列应用

    一.类相关属性 接口BlockingQueue<E>定义: public interface BlockingQueue<E> extends Queue<E> { ...

  5. JavaScript arguments你不知道的秘密

    (function test(x){ x=10; console.log(arguments[0], x); //undefined, 10 })(); (function test(x){ x=10 ...

  6. 调试android chrome web page简明备忘

    必备工具 adb tools.android chrome 先开启手机调试模式 adb forward tcp:9919 localabstract:chrome_devtools_remote 成功 ...

  7. R1(上)—R关联规则分析之Arules包详解

    Arules包详解 包基本信息 发布日期:2014-12-07 题目:挖掘关联规则和频繁项集 描述:提供了一个表达.处理.分析事务数据和模式(频繁项集合关联规则)的基本框架. URL:http://R ...

  8. 【CodeForces】698 C. LRU

    [题目]C. LRU [题意]给定空间为k的背包和n个物品,每次每个物品有pi的概率加入(Σpi=1),加入时若发现背包中已有该物品则不改变,若背包满k个物品后再加入新物品则弹出最早加入的物品,求加入 ...

  9. 【CF802C】 Heidi and Library (hard)(费用流)

    题目链接 感觉跟餐巾计划问题有点像.费用流. 决定每天买不买不太好搞,不如先把所有东西都买进来,再卖掉不必要的. 拆点,每个点拆成\(x,y\). 源点向每个点的\(x\)连费用为当天的价格,流量为1 ...

  10. flex图片布局

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>f ...