C++快速文件输入输出
转载请注明:
仰望高端玩家的小清新 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++快速文件输入输出的更多相关文章
- [软件推荐]快速文件复制工具(Limit Copy) V4.0 绿色版
快速文件复制工具(Limit Copy)绿色版是一款智能变频超快复制绿色软件. 快速文件复制工具(Limit Copy)功能比较完善,除了文件复制还可以智能变频,直接把要复制的文件拖入窗口即可,无需手 ...
- C++IO类&文件输入输出
C++IO类&文件输入输出 istream(输入流)类型,提供输入操作. ostream(输出流)类型,提供输出操作. cin,一个istream对象,从标准输入读取数据. cout,一个os ...
- Java通过NIO实现快速文件拷贝的代码
将内容过程重要的内容片段做个记录,下面的内容段是关于Java通过NIO实现快速文件拷贝的内容. public static void fileCopy( File in, File out ) thr ...
- python 中文件输入输出及os模块对文件系统的操作
整理了一下python 中文件的输入输出及主要介绍一些os模块中对文件系统的操作. 文件输入输出 1.内建函数open(file_name,文件打开模式,通用换行符支持),打开文件返回文件对象. 2. ...
- IO库----IO类,文件输入输出,string流
一.IO类 1.IO库类型和头文件表: 头文件 类型 iostream istream,wistream 从流读取数据 ostream,wostream 向流写入数据 iostream,wiostre ...
- 第五次程序设计作业 C++计算器雏形 调用文件输入输出
一.C++计算器作业系列链接 第三次作业:C++计算器雏形 第三次作业附加:代码规范 第四次作业:命令行的调用及计算 MyGithub 二.本次作业相关 要求:第五次程序设计作业 根据这一次的作业要求 ...
- 文件输入输出实例&Ptask的编写
前言 最近在写Ptask,顺便了解了如何进行文件读入输出.而在Ptask中最重要,也是最最容易出bug的地方就是文件操作.那么如何进行文件输入输出,在程序中起到重要作用呢? 输入 首先为了保证可以在控 ...
- freopen - C/C++文件输入输出利器
freopen以前经常使用,比较方便,可以当作模板,在中间替换为自己的代码即可使用. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h&g ...
- 文件输入输出C++操作
基于C++的文件操作 在C++中,有一个stream这个类,所有的I/O都以这个"流"类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符: 1.插入器(& ...
随机推荐
- JAX-WS搭建WebService和客户端访问程序
开发环境:myeclipse8.6+jdk1.6.0_29+tomcat6.0.37 XFire搭建webservice: http://www.cnblogs.com/gavinYang/p/352 ...
- Win7 32位安装Oracle11g R2 图解示例
Win7 32位操作系统安装Oracle11g R2 图解示例.废话不说了,直接上图. 1.下载的两个oracle 11gR2压缩包解压到单独的文件夹中. 2.找到解压的database文件夹中的Se ...
- 修改tomcat的Response Hearder 头中的Server信息
如图: Server: Apache-Coyote/1.1 这个信息给入侵者提供了一定的指示作用.为了安全起见,要求更改这个信息.那么我们就来修改一下试试,非常简单,只要在Connector中添加se ...
- linux的MySQL设为开机启动
linux开启启动的程序一般放在/etc/rc.d/init.d/里面,/etc/init.d/是其软连接 mysql设为linux服务cp /usr/local/mysql5/share/mysql ...
- 针对移动设备的CSS3布局
针对移动设备的CSS3布局 一些专业人士预测五年内移动设备将击败普通电脑成为网页浏览领域的霸主,不管这个预言是否应验,让网页在移动设备上较好的显示已经成为网页设计师和开发者的重要任务,本教程学习用CS ...
- 【CodeForces】671 D. Roads in Yusland
[题目]D. Roads in Yusland [题意]给定n个点的树,m条从下往上的链,每条链代价ci,求最少代价使得链覆盖所有边.n,m<=3*10^5,ci<=10^9,time=4 ...
- 【leetcode 简单】第三十八题 两数之和 II - 输入有序数组
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值( ...
- 【leetcode 简单】第四题 罗马数字转整数
罗马数字包含以下七种字符:I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并列 ...
- 2017ACM暑期多校联合训练 - Team 6 1010 HDU 6105 Gameia (博弈)
题目链接 Problem Description Alice and Bob are playing a game called 'Gameia ? Gameia !'. The game goes ...
- react 修改state某一属性值
1.state // 筛选框相关数据 searchSelect: { term: { value: '学期', key: '', options: [] }, type_of_personnel: { ...