0x01-文件读写方法

使用C语言中的freopen()函数进行打开文件并重定向输入输出。示例如下:

1
2
3
4
5
6
7
8
9
10
#include<iostream>;
using namespace std;
int main()
{
freopen("testfile.txt","w",stdout);

for(int i=0;i<10;i++)
cout<<i<<" ";
return 0;
}

这样,你就可以使用普通的cin,cout来进行文件的输入输出了。当然,也可以使用scanf()、printf()等输入输出函数。

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>;
#include<cstdio>;
using namespace std;
int main()
{
freopen("testfile.txt","w",stdout);

for(int i=0;i<10;i++)
printf("%d",i);
return 0;
}

输出结果应该为0-9的一行数字。
其中,freopen()的第一个参数为文件路径+文件名,即文件所在的相对路径或绝对路径。第二个参数为描述符:常用的有r(read,读)、w(write,写)等。第三个参数为被重定向的流一般有stdin,stdout和stderr。
下面,就来详解一下这三个参数。

0x02 freopen()参数的说明

1. char *FileName

第一个参数填文件名。平时做题或者比赛时,因为数据基本上都会和程序放在一块,所以直接写文件名即可。程序会读取同目录下的对应文件。
而你如果把数据放在了子文件夹"SubDir"中,那么就应该使用相对路径,即相对当前目录的位置。例如:

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>;
#include<cstdio>;
using namespace std;
int main()
{
freopen("SubDir/testfile.txt","w",stdout);

for(int i=0;i<10;i++)
printf("%d",i);
return 0;
}

但是,如果你的数据放在了父级目录呢?
那就使用绝对路径。即相对于你盘符(或者说根目录)的路径。

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>;
#include<cstdio>;
using namespace std;
int main()
{
freopen("C:\\Users\\Administrator\\Desktop\\testfile.txt","w",stdout);

for(int i=0;i<10;i++)
printf("%d",i);
return 0;
}

注意,Windows平台下,文件路径使用的是反斜杠\。而编译器会理所当然地把你的\\当成是在转义——所以,你要转义你的\。也就是使用双反斜杠\\
(不是,原来Markdown里\\也是转义吗)

2. char *RestrictMode

这个没什么好说的,一般只用读写足矣,
r(read,读)、w(write,写)。

3. char *RestrictStream

输入输出重定向至的流。
一般使用标准输入输出流,即使用stdin(输入)、stdout(输出)。
stderr是标准错误输出设备流。在默认情况的下,stdout会缓冲——只有当换行的时候,缓冲中的内容才会输出到你的屏幕。
而stderr则是没有缓冲的,会直接输出。在你想读写文件时,请不要用stderr。它会直接输出到你的屏幕上(输出错误信息用的)。也就是你程序的运行界面。
当然,这玩意平时写代码几乎用不到。

0x03 文件读写的加速

文件读写加速的方法也很简单。主要有以下几种:

1. 在一开始关闭同步流加速

使用以下方法:

1
2
3
4
5
6
7
8
9
10
11
#include<iostream>;
#include<cstdio>;
using namespace std;
int main()
{
freopen("testfile.txt","w",stdout);
ios::sync_with_stdio(false);
for(int i=0;i<100;i++)
printf("%d",i);
return 0;
}

加一行代码,把同步流设置成false。注意,一定要在一开始加!否则你都输出完了还关啥…
把输出改为输出一万个数(0-9999),看看加了和不加的区别如何:

1
2
3
Process returned 0 (0x0)   execution time : 0.455 s
---------------------------------------------------
Process returned 0 (0x0) execution time : 0.428 s

上面是没加的,下面是加了的。
经过多次试验可以发现,关了同步流比没关大概要快0.03秒左右。如果数据更大,那么时间差也会更大。

2. 使用"\n"换行

换行时,你可能会使用endl。推荐使用换行符代替endl换行——只不过需要注意平台差异,Windows/Linux/Mac的换行符可能不一样。在Windows下,换行符为\r\n,而在Linux下,换行符为\n,Mac则是\r
同样地,我们来对比一下用时:
A组:

1
2
3
4
5
6
7
8
9
10
#include<iostream>;
using namespace std;
int main()
{
freopen("testfile.txt","w",stdout);
ios::sync_with_stdio(false);
for(int i=0;i<10000;i++)
cout<<i<<endl;
return 0;
}

B组:

1
2
3
4
5
6
7
8
9
10
#include<iostream>;
using namespace std;
int main()
{
freopen("testfile.txt","w",stdout);
ios::sync_with_stdio(false);
for(int i=0;i<10000;i++)
cout<<i<<"\n";
return 0;
}

用时对比:

1
2
3
Process returned 0 (0x0)   execution time : 0.551 s // A组
---------------------------------------------------
Process returned 0 (0x0) execution time : 0.440 s // B组

我们可以明显地看到,使用换行符"\n"会快很多。
(tips:这些加速也是基本的卡常知识)