-
C++
中的文件输入
/
输出
(1)
原作:
Ilia Yordanov, loobian@
简介
<
/p>
本教程将以
C++
最基本的文件
I/O
(输出
/
输出)
开始。此后,我将从更深入
的方面,为你展示一些技巧,并分析给出一些有用的函数。<
/p>
你需要对
C++
有一个较好的理解,否则这个教程于你而言将是陌生而毫无用
处。
你的第一个程序
首先我将给出一段代码,接着再逐行进行解释。我们的第一
个程序将建立一
个文件,并写入一些字符:
#include
void main()
//
程序从这里开始运行
{
ofstream
SaveFile(“cpp
-
”);
SaveFile << “Hello World, from
and
Loobian!”;
();
}
仅仅如此吗?没错!这个程序将在
当前运行目录下建立一个名为
的文件,并向它写入
“Hello World, from
and
Loobian!”
。
下面给出各行的含义:
#include
——
你需要包含此文件以使用
C++
的文件输入
/
输出
函数。注意:一旦包含了这个文件,你不再需要(为了使用
cout/cin
)包含
iostream.h
,因为
fstream.h
已经自动包含了它。
在这个头文件中声明了若干个类,
包括
p>
ifstream
,
ofstream
p>
及
fstream
,
它
们都继承自
istream
和
p>
ostream
类。
ofstream
SaveFile(“cpp
-
”);
1
)
ofstream
即
“output file stream
(输出文
件流)
”
。它将建立一个句柄
(
handle
),以便我们以后能以一个文件流的形式写入文件。
p>
2
)
SaveFile
——
这是文件句柄的名字,当然,你
还可以换用任何一个你想
要的名称。
3
)
(“cpp
-
”);
——
< br>打开名为
的文件。如果程序运行
的当前目录已经存在这样一个文件,
则它将被替换掉;
万一不存
在,
程序也会为
你创建一个为文件,你不必为此而担心。
现在,让我们稍微深入一点点。首先,我要指出的是:
ofstream
是一个类。
因此
< br>ofstream SaveFile(“cpp
-
”)
;
这一语句将创建一个该类的对象;而我
们在括号中所传递的参
数实际上将传给构造函数:
在这里我们将我们要建立的文
件的名
称作为实际参数传递给了该类的构造函数。
当然,
我们还可以传
递其它的
一些信息,不过我以后再对其进行讲解。
SaveFile << “Hello World,
from
and
Loobian!”;
——
“
p>
<<
”看起来是不是很亲切?不错,想必你已经在
< br>cout <<
中见到过。这是一
个预定义好的运算符
。
不管怎么说,
这行语句所做的,
是将
上面的那段文本写入
文件。正如前面所提到的,
SaveFil
e
是一个文件句柄,它关联一个打开的流式文
件。所以,我们只
须输入句柄名,再跟着输入“
<<
”,然后接着写下一串用引号
括起来的文本,
就可以实现对文件的写入。
如果我们想写入的是某个变量的值而
不是带引号的文本,也只须像通常使用
cout <<
一样将变量传递给句柄对象,
像这样:
SaveFile << variablename;
就可以了!
();
——
既然我们打开了一个流文件,
那么当我们用完它之
后,就必须
关闭它。
SaveFile
是
ofst
ream
类的一个对象,而该类
(
of
stream
)
有一
个用于关闭文件的
成员函数,即
close()
函数。
因此,我们只要依次输入文件句
柄名,点号和
close()<
/p>
,就可以关闭该文件!
注意:
一旦你关闭文件,在你重新打开它以前,就再不能对它进行访问。
以上就是一个可以写文件的最简单
程序。的确很容易!不过,正如你即将在
以后部分的教程中所看到的,还有更多的东西要
学呢!
本文引用通告地址:
/Kusk/services/trackbacks/
=================
C++
中的文件输入
/
输出(
2<
/p>
):读取文件
C++
中的文件输入
/
输出
(2)
原作:
Ilia Yordanov, loobian@
读取文件
你已经看到了应该如何写文件。
现
在,
当我们已经得到
文件时,
我们将要读取它,并且将内容打印在屏幕上。
首先,我要指出的是,有很多种方法可以读取文件。以后我会向你们介绍所
有的方法(就
我所知的)。此刻,我先向你展示最佳的方法(我认为的)。
正如你已经熟悉的——我将首先给出一段程序代码,然后,我会详细地对它
进行解释说明
:
#include
void main()
//
程序从这里开始
{
ifstream
OpenFile(
char ch;
while(!())
{
(ch);
cout << ch;
}
();
}
p>
你想必已经了解首行的意义所在,而剩下的部分将由我为你解释。
ifstream
OpenFile(“cpp
-
”)
——
我猜它对现在的你而言多少会<
/p>
熟悉些!
ifstream
表示
“input file s
tream
(
p>
输入文件流
)
”
。
在前一节的程序中,出
现的则是
ofstream
,它的意义是
“output file stream
(
输出文件流
)
”
。前一节的程
序是进行文件的写操作,这就是它用
“o
utput
(
输出
)
< br>”
来表示的原因。而本节的程
序则是读取一个文件,
p>
这就是它用
“input
(
输入
)
”
来表示的原因。
p>
这一行剩下的代
码于你而言应当是熟悉的了:
OpenFile
是
ifstream
类的一个对象,它将关联一个
输入文件流;而用引号括住的内容,就是将要打开的文件
的名称。
请注意:这里没有对要打开的文件是否存在进行测试
!以后我将向你指出如
何进行检测。
char ch;
——
声明一个字符数组(
array of type
char
)。只是有一点要提
醒你:这样的数组(
arrays
)只能存储一个
ASCI
I
字符。
while(!())
——
如果已经到达文件末尾,
eof( )
函数将返回
一个非零值。
因此我们所设计的这个循环将一直持续
,
直至我们的文件操作到达
文件末尾。这样我们就可以遍历整个
文件,以便对它进行读取。
(ch);
——
OpenFile
是类
ifstream
的一个对象。
该类声明了一
个名为
get( )
的成员函数。只要我们拥有该对象,我们自然就可以调用这个函
数。
get(
)
函数从相应的流文件中读出一个字符,<
/p>
并将其返回给变量。
在本例中,
get(
)
函数只带一个参数——用于存储所读取的字符的变量。所以,调用
(ch)
后程序将会从
OpenFile
< br>流中读取一个字符并存入变量
ch
中。
< br>
注意:
如果你再次调用该函数,
它将读取下一个字符,
而不是原来的那一个!
你过后将理解为
什么会这样。
这就是我们要不断反复循环直至读操作到达文件
尾的原因。每循环一次,我
们将读出一个字符并将它保存在
ch
中。
cout << ch;
——
显示
c
h
变量值,它保存了读取得到的字符。
();
——
我们打开了一个流式文件,
p>
就需要关闭它。
使用
close()
函数即可将它关闭,这和前一节的一样!
注
意:
一旦你关闭了一个文件,在你重新打开它之前,你不能再对它进行访
问。
< br>大功告成了!我希望你能明白我的解释。当你编译并运行这个程序的时候,
它应当
会输出:
“Hello World, from
and Loobian!”
本文引用通告地址:
/Kusk/services/trackbacks/
===============
C++
< br>中的文件输入
/
输出(
3
):掌握输入
/
输出流
C++
中的文件输入
/
输出
(3)
原作:
Ilia Yordanov,
loobian@
掌握输入
/
输出流
在这一
章里,我会提及一些有用的函数。我将为你演示如何打开一个可以同
时进行读、写操作的
文件;此外,我还将为你介绍其它打开文件的方法,以及如
何判断打开操作是否成功。因
此,请接着往下读!
到目前为止,我已为你所展示的只是单一
的打开文件的途径:要么为读取而
打开,要么为写入而打开。但文件还可以以其它方式打
开。迄今,你应当已经认
识了下面的方法:
ifstream
OpenFile(“c
pp-
”);
噢,这可不是唯一的方法!正如以前所提到的,以上的代码
创建一个类
ifstream
的对象,并将文件的名字传递给它
的构造函数。但实际上,还存在有不
少的重载的构造函数,它们可以接受不止一个的参数
。同时,还有一个
open()
函数可以做同样的事情。下面是
一个以上代码的示例,但它使用了
open()
函数:
ifstream
OpenFile;
(“cpp
-<
/p>
”);
你
会问:
它们之间有什么区别吗?哦,
我曾做了不少测试,
结论是没有区别!
只不过如果你要创建一个文件句柄但不想立刻给它指
定一个文件名,
那么你可以
使用
ope
n()
函数过后进行指定。顺便再给出一个要使用
open()
函数的例子:如
果你打开一个文件,然后关闭了它,又打算用同
一个文件句柄打开另一个文件,
这样一来,你将需要使用
ope
n()
函数。
考虑以下的代码示例:
#include
void
read(ifstream &T)
//pass the file
stream to the function
{
//the method to read a
file, that I showed you before
char ch;
while(!())
{
(ch);
cout <<
ch;
}
cout <<
endl <<
}
void
main()
{
ifstream T(
read(T);
();
(
read(T);
();
}
p>
据此,
只要
和
p>
并存储了文本内容,
你将看到这些内容。<
/p>
现在,
该向你演示的是,
文件名并不是你唯一可以向
open()
函数或者构
造函
数(其实都一样)传递的参数。下面是一个函数原型:
ifstream OpenFile(char
*filename, int open_mode);
你应当知道
filename
表示文件
的名称(一个字符串),而新出现的则是
open_mode
(
打开模式)。
open_mode
的值用来定义以怎样的方式打
开文件。下
面是打开模式的列表:
名称
ios::in
ios::out
ios::app
ios::ate
ios::trunk
ios::nocreate
ios::noreplace
ios::binary
描述
打开一个可读取文件
打开一个可写入文件
你写入的所有数
据将被追加到文件的末尾,
此
方式使用
ios::out
你写入的所有数据将被追加到文件的末尾,
此
方式不使用
ios::out
删除文件原来已存在的内容(清空文件)
如果要打开的文件并不存在,
那么以此参数调
< br>用
open()
函数将无法进行。
如果要打开的文件已存在,试图用
open()
函
数打开时将返回一个错误。
以二进制的形式打开一个文件。
实际上,以上的值都属于一个枚举类型的
int
常量
。但为了让你的编程生涯
不至于太痛苦,你可以像
上表所见的那样使用那些名称。
下面是一个关于如何使用打开模式的例子:
#include
void main()
{
ofstream
SaveFile(
SaveFile <<
();
}
p>
正如你在表中所看到的:使用
ios::ate
将会从文件的末尾开始执行写入。
如果我没有使用它,
原来
的文件内容将会被重新写入的内容覆盖掉。
不过既然我
已经使用
了它,那么我只会在原文件的末尾进行添加。所以,如果
原有的
内容是这样:
Hi! This is test from
!
那么执行上面的代码后,程序将会为它添上“
That’s <
/p>
new!
”,因此它看起
来将变成这样:
Hi! This is test from
-
!That’s
new!
假如你打算设置不止一个的打开模式标志,只须使用
OR
操作符或者是
|
,
像这样:
ios::ate | ios::binary
我希望现在你已经明白“打开模式”是什么意思了!
现在,是时候向你展示一些真正有用的东西了!我敢打赌你现在还不知道应
当怎样打开一个可以
同时进行读取和写入操作
的文件!下面就
是实现的方法:
fstr
eam
File(“cpp
-
”,ios::in |
ios::out);
实际上,这
只是一个声明语句。我将在下面数行之后给你一个代码示例。但
此时我首先想提及一些你
应当知道的内容。
上面的代码创建了一个名为“
File
”的流式文件的句柄。如你所知,它是
fs
tream
类的一个对象。当使用
fstream
时,你应当指定
ios::in
和
< br>ios::out
作为文件的打开模式。这样,你就可以同时对文件进行读、写,
而无须创建新的
文件句柄。噢,当然,你也可以只进行读或者写的操作。那样的话,相应
地你应
当只使用
ios::in
或者只
使用
ios::out
——
要思考的问题是:如果你打算这
么做,为什么你不分别用
ifstream
及
ofstream
来实现呢?
下面就先给出示例代码:
#include
void main()
{
fstream
File(
File <<
//
将
p>
“Hi!”
写入文件
static char str[10];
p>
//
当使用
static
< br>时,数组会自动被初始化
//
即是被清空为零
(ios::beg);
//
回到文件首部
//
此函数将在后面解释
File >> str;
cout << str
<< endl;
();
}
OK
,这儿又有一些新东西,所以
我将逐行进行解释:
fstream File(“”, ios::in |
ios::out);
——
此行创
建一个
fstream
对象,
执行时将会以读
/
写方
式打开
文件。
这意味着你
可以同时读取文件并写入数据。
File << “Hi!”;
——
我打赌你已经知道它的意思了。
static char str[10];
——
这将创建一个容量为
10
的字符数组。我
猜
s
tatic
对你而言或者有些陌生,如果这样就忽略它。这只不过会在创建数组
的同时对其进行初始化。
(ios::beg);
——
OK
,我要让你明白它究竟会做
些什么,
因此我将以一些有点儿离题、但挺重要的内容开始我的解释。
< br>
还记得它么:
while(!())
{
(ch);
cout << ch;
}
你是不是曾经很想知道那背后真正执行了什么操作?不管是或不是,
我都将
为你解释。
这是一个
while
型循环,
它会一直反复,
直至程序的操作到达文件的<
/p>
尾端。
但这个循环如何知道是否已经到了文件末尾?嗯,
当你读文件的时候,
会
有一个类似于“内置指针
(
inside-pointer
)”的东西,它表明你读取(
写入也
一样)已经到了文件的哪个位置,就像记事本中的光标。而每当你调用
(ch)
的时候,它会返回当前位置的字符,存储在
ch
变量中,并将
这一内置指针向前移动一个字符。
因此下次该函数再被调用时,
它将会返回下一
个
字符。而这一过程将不断反复,直到读取到达文件尾。所以,让我们回到那行
代码:
p>
函数
seekg()
将把内置指针定位到指
定的位置
(依你决定)
。
你可以使用:
ios::beg
——
可将它移动到文件首端
ios::end
——
可将它移动到文件末端
或者,你可以设定向前或向后跳转的字符数。例如,如果你要想定位到当前
位置的
5
个字符以前,你应当写:
(-5);
如果你想向后跳过
40
个字符,则应当写:
(40);
同时,我必须指出,函数
seekg()
是被重载的,它也可以带两个参数。另一
个版本是这样子的:
(-5,ios::end);
在这
个例子中,你将能够读到文件文本的最后
4
个字符,因为:
p>
1
)你先到达了末尾(
< br>ios::end
)
2
)你接着到达了末尾的前五个字符的位置(
-5
)
为什么你会读到
4
个字符而不是
5
个?噢,
只
须把最后一个看成是
“丢掉了”
,
因为
文件最末端的“东西”既不是字符也不是空白符,那只是一个位置
(译注:
或许
ios::end
所“指”的根本已经超出了文
件本身的范围,确切的说它是指向
文件最后一个字符的下一个位置,
有点类似
STL
中的各个容器的
e
nd
迭代点是指
向最后一个元素的下一位置。这样设计可能是便
于在循环中实现遍历)。
你现在可能想知道为什么我要使用到
这个函数。呃,当我把“
Hi
”写进文件
之后,
内置指针将被设为指向其后面??也就是文件的末尾。
因此我必须将内置
指针设回文件起始处。这就是这个函数在此处的确切用途。
File
>>
str;
——
这也是新鲜的玩意儿!噢,我确
信这行代码让你想起
了
cin >>
.
实际上,它们之间有着相当的关联。此行会从文件中读取一个单词,
< br>然后将它存入指定的数组变量中。
例如,如果文件中有这样的文本片断:
Hi! Do you know me?
使用
File
>>
str
,则只会将“Hi!”输出到
str
数组中。你应当已经注意到
了,它实际上是将空格作为单词的分隔符进行读
取的。
由于我存入文件中的只是单独一个“
< br>Hi!
”,我不需要写一个
while
< br>循环,
那会花费更多的时间来写代码。
这就是我使用此方
法的原因。
顺便说一下,
到目
前为止,
我所使用的读取文件的
while
循环
中,
程序读文件的方式是一个字符一
个字符进行读取的。然而你
也可以一个单词一个单词地进行读取,像这样:
char str[30];
//
每个单词的长度不能超过
30
个字符
while(!())
{
OpenFile >>
str;
cout <<
str;
}
你也可以一行一行地进行读取,像这样:
char line[100];
//
每个整行将会陆续被存储在这里
while(!())
{
e(line,100);
//
100
是数组的大小
cout <<
line << endl;
}
你现在可能想知道应当使用哪种方法。嗯,我建议你使用逐行
读取的方式,
或者是最初我提及的逐字符读取的方式。而逐词读取的方式并非一个好的方
案,
因为它不会读出新起一行这样的信息,
所以如果你的文件中
新起一行时,
它将不
会将那些内容新起一行进行显示,而是加在
已经打印的文本后面。而使用
getline()
或者
get()
都将会向你展现出文件的本来面目!
现在,我将向你介绍如何检测文件打开操作是否成功。实现上,好的方法少
之又少,我将都会涉及它们。需要注意的是,出现“
X
”的时候,它实际可以以
“o”、
“i”来代替,或者也可以什么都不是(那将是一个
fstream
对象)。
例
1
< br>:最通常的作法
Xfstream
File(“cpp
-
”);
if (!File)
{
cout << “Error opening the file!
Aborting…
n”;
exit(1);
}
例<
/p>
2
:如果文件已经被创建,返回一个错误
ofstream File(
if(!File)
{
cout << “Error
opening the file!
Aborting…
n”;
exit(1);
}
例<
/p>
3
:使用
fail()
< br>函数
ofstream
File(
if(())
{
cout << “Error opening the
file!
Aborting…
n”;
exit(1);
}
例<
/p>
3
中的新出现的东西,是
fail()<
/p>
函数。如果有任何输入
/
输出错误(不是
在文件末尾)发生,它将返回非零值。
我也要讲一些我认为非常重要的内容!例如,如果你已经创建一个流文件对
象,但你没
有进行打开文件操作,像这样:
ifstream File;
//
也可以是一个
ofstream
这样,我们就拥有一个文件句柄,但我们仍然没有打开文件。如果你打算迟
些打开它,那么可以用
open()
函数来实现,我
已经在本教程中将它介绍了。但
如果在你的程序的某处,
你可能
需要知道当前的句柄是否关联了一个已经打开的