【杂谈】比赛时的测试方式——文件操作入门
1.引入
C++中读写文件的方式有两种:流式和I/O方式。信息学竞赛中一般使用流式文件操作。分为两种:文件指针FILE
和stream
类的文件流。
2.输入输出流
流是磁盘或其他外围设备关联的数据或目的地。通俗来讲,C++程序通过流来与外界交互。在程序开始执行时,stdin
、stdout
、stderr
这三个流已经处于打开状态,分别为标准输入、标准输出和标准错误。前面两个我们已经很熟悉了,可以简单理解成cin
和cout
。标准错误,顾名思义,就是发生错误导致stdout
不能正常打开时使用它报告错误。
3.文件重定向
3.1.语法讲解
在信息学竞赛中通常只需要同时打开一个输入文件和一个输出文件,因此可以使用freopen
函数实现输入输出文件重定向,将stdin
,stdout
等已经打开的文件流重定向到指定文件。需要包含cstdio
头文件。
freopen(Filename,mode,stream);
其中,Filename
为文件名,应当是一个字符串形式。
mode
为打开模式。有两种合法值:
“r” | 以只读方式打开文本文件,若文件不存在则操作失败 |
---|---|
“w” | 以只写方式打开文件,并删除文件已存在的内容,若文件不存在则创建该文件 |
当时用只读方式打开文件时,后面的参数应是stdin
,否则就是stdout
。
freopen
的具体使用如下:
3.2.例题1——标题统计
题目背景
NOIP2018 普及组 T1
题目描述
凯凯刚写了一篇美妙的作文,请问这篇作文的标题中有多少个字符? 注意:标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字符数时,空格和换行符不计算在内。
输入格式
输入文件只有一行,一个字符串 s s s。
输出格式
输出文件只有一行,包含一个整数,即作文标题的字符数(不含空格和换行符)。
输入输出样例
输入 #1
234
输出 #1
3
输入 #2
Ca 45
输出 #2
4
提示
样例 1 说明
标题中共有 3 个字符,这 3 个字符都是数字字符。
样例 2 说明
标题中共有 5 5 5 个字符,包括 1 1 1 个大写英文字母, 1 1 1 个小写英文字母和 2 2 2 个数字字符, 还有 1 1 1 个空格。由于空格不计入结果中,故标题的有效字符数为 4 4 4 个。
数据规模与约定
规定
∣
s
∣
|s|
∣s∣ 表示字符串
s
s
s 的长度(即字符串中的字符和空格数)。
对于
40
%
40\%
40% 的数据,
1
≤
∣
s
∣
≤
5
1 ≤ |s| ≤ 5
1≤∣s∣≤5,保证输入为数字字符及行末换行符。
对于
80
%
80\%
80% 的数据,
1
≤
∣
s
∣
≤
5
1 ≤ |s| ≤ 5
1≤∣s∣≤5,输入只可能包含大、小写英文字母、数字字符及行末换行符。
对于
100
%
100\%
100% 的数据,
1
≤
∣
s
∣
≤
5
1 ≤ |s| ≤ 5
1≤∣s∣≤5,输入可能包含大、小写英文字母、数字字符、空格和行末换行符。
3.3.代码示例和具体使用方法
分析题目,很容易就可以写出代码。
#include<iostream>
using namespace std;
int main(){
int len=0;
string s;
while(cin>>s)
len+=s.length();
cout<<len<<endl;
return 0;
}
在竞赛中,我们要把它变成文件输入输出的形式才能正确提交。
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
freopen("title.in","r",stdin);
freopen("title.out","w",stdout);
int len=0;
string s;
while(cin>>s)
len+=s.length();
cout<<len<<endl;
return 0;
}
运行程序,发现一闪而过。别忘了,既然是文件输入输出,那得有文件输入。创建一个文件title.in
,将输入样例1复制进去并保存。
新建一个title
文件夹。将cpp
源文件移动到里面,并在里面新建一个txt
文件,将其后缀名改为.in
。然后复制输入样例1进去并保存。
接下来再运行程序,发现还是一闪而过。但不同的是,文件夹里多出了一个title.out
文件,打开它,里面就是程序的输出了。
3.4.宏定义扩展和文件输入输出扩展
在洛谷等OJ中,程序只能使用流式输入输出,那怎样在本地使用文件输入输出,在OJ测评时使用流式输入输出呢?
最简单粗暴的方式是把freopen
注释掉。但在这里要介绍另一种方法。
大部分OJ在测评时都会定义ONLINE_JUDGE
这个宏,只需要判断是否定义了这个宏,就可以判断是否要运行freopen
这一段了。以上面的例题为例。
#ifndef ONLINE_JUDGE//从字面意思理解,就是如果没定义一个宏
freopen("输入文件名","r",stdin);
freopen("输出文件名","w",stdout);
#endif//和上面的ifndef相呼应,代表上面那个ifndef能影响到的代码的结尾
有ifndef
,那是不是有ifdef
呢?当然有,其使用方法和ifndef
差不多。为了节省时间这里就不再赘述了。
有ifdef
,也就会有if
。和普通的if差不多,宏if
的使用示例如下:
#if 1+1==2
cout<<"1+1=2\n";
#endif
以上这些通过条件来选择是否编译的语句叫做条件编译。
undef
的作用是取消定义一个宏。比如:
#include<iostream>
using namespace std;
#define MAXN 2020
#undef MAXN
int main(){
int a[MAXN];
cout<<MAXN<<endl;
return 0;
}
如果运行上面那段的代码,就会报错。这是因为MAXN
这个宏已经被释放掉了。不能再使用了。
3.5.小技巧
如果想进一步节省时间,可以把重定向文件输出的部分注释掉,这样就可以直接在控制台查看输出,非常方便。比如:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
#ifndef ONLINE_JUDGE
freopen("title.in","r",stdin);
//freopen("title.out","w",stdout);
#endif
int ans=0;
string s;
while(cin>>s)
ans+=s.length();
cout<<ans;
return 0;
}
喜欢就订阅此专辑吧!
【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。
欢迎扫码关注蓝胖子编程教育