把参数书输入输出到指定文件

来源:互联网 发布:永恒之塔淘宝双倍礼包 编辑:程序博客网 时间:2024/05/02 04:49

c语言编程时,如何将文件的内容(内容中有汉字)输出

 int main()
{ifstream  a1("a.txt",ios::in);  //打开这个文件
  然后看文件里有什么了,如果是字符串数组 则
   string a[10];
  for(int i=0;i<10;i++)
     {a1>>a[i];
      cout<<a[i]<<endl;
   a1.close();
}

int  main  
{
string  a;
printf("中国!",&a);

}

输出结果为:中国

当字符串读,应该就可以了,再把读到的字符串输出

从键盘输入内容:#include "stdio.h"main(int argc, char *argv[])    { FILE *fp;       char string[81];/*字符数组用于暂存输入输出的字符串*/       if(argc>2)            /*参数太多,提示 出错*/          {  printf("Too many parameters…\n\n");         printf("Usage: 可执行文件名  filename\n");              exit(0);          }if(argc= =1)                      /*缺磁盘文件名,提示输入*/      { printf("Input the filename: ");        gets(string);/*借用string暂存输入的文件名*/        argv[1]=(char *)malloc(strlen(string)+1);/*给文件名参数申请内存空间*/        strcpy(argv[1],string);/*复制文件名到形参中*/      }  if ((fp=fopen(argv[1],"w"))==NULL)   /*打开文件失败*/      {  printf("can not open this file\n");   exit(0);      }  /*从键盘上输入字符串,并存储到指定文件中*/  printf("Input a string: "); gets(string);/*从键盘上输入字符串*/  fputs(string, fp);/*存储到指定文件*/  fclose(fp);/*重新打开文件,读出其中的字符串,并输出到屏幕上*/    if ((fp=fopen(argv[1],"r"))==NULL)   /*打开文件失败*/         {  printf("can not open this file\n");            exit(0);         }    fgets(string, strlen(string)+1, fp);/*从文件中读一个字符串*/    printf("Output the string: "); puts(string);/*将字符串输出到屏幕上*/    fclose(fp);  }

C++ 文件的输入输出[复制链接]

  
HuangSteve
HuangSteve当前离线
威望
45 点
C3P币
59030 元
贡献值
2318 点
推广邀请能量
5815 焦耳
最后登录
2012-5-1
注册时间
2000-7-9
帖子
42885
精华
39
积分
59030
阅读权限
200
UID
21
QQ阿里旺旺查看详细资料 IP卡 狗仔卡
 
主题帖
发表于 2008-3-23 09:46:33|只看该作者
(1):你的第一个程序

简介

本教程将以C++最基本的文件I/O(输出/输出)开始。此后,我将从更深入的方面,为你展示一些技巧,并分析给出一些有用的函数。

你需要对C++有一个较好的理解,否则这个教程于你而言将是陌生而毫无用处。

你的第一个程序

首先我将给出一段代码,接着再逐行进行解释。我们的第一个程序将建立一个文件,并写入一些字符:
#include <fstream.h>

void main() // 程序从这里开始运行
{

ofstream SaveFile("cpp-home.txt");

SaveFile << "Hello World, from www.cpp-home.com and Loobian!";

SaveFile.close();
}

仅仅如此吗?没错!这个程序将在当前运行目录下建立一个名为cpp-home.txt的文件,并向它写入"Hello World, from www.cpp-home.com and Loobian!"。

下面给出各行的含义:

#include <fstream.h> —— 你需要包含此文件以使用C++的文件输入/输出函数。注意:一旦包含了这个文件,你不再需要(为了使用cout/cin)包含iostream.h,因为fstream.h已经自动包含了它。

在这个头文件中声明了若干个类,包括ifstream,ofstream及fstream,它们都继承自istream和ostream类。

ofstream SaveFile("cpp-home.txt");

1)ofstream即"output file stream(输出文件流)"。它将建立一个句柄(handle),以便我们以后能以一个文件流的形式写入文件。

2)SaveFile —— 这是文件句柄的名字,当然,你还可以换用任何一个你想要的名称。

3)("cpp-home.txt"); —— 打开名为cpp-home.txt的文件。如果程序运行的当前目录已经存在这样一个文件,则它将被替换掉;万一不存在,程序也会为你创建一个为文件,你不必为此而担心。

现在,让我们稍微深入一点点。首先,我要指出的是:ofstream是一个类。因此ofstream SaveFile("cpp-home.txt");这一语句将创建一个该类的对象;而我们在括号中所传递的参数实际上将传给构造函数:在这里我们将我们要建立的文件的名称作为实际参数传递给了该类的构造函数。当然,我们还可以传递其它的一些信息,不过我以后再对其进行讲解。

SaveFile << "Hello World, from www.cpp-home.com and Loobian!"; —— "<<"看起来是不是很亲切?不错,想必你已经在cout << 中见到过。这是一个预定义好的运算符。不管怎么说,这行语句所做的,是将上面的那段文本写入文件。正如前面所提到的,SaveFile是一个文件句柄,它关联一个打开的流式文件。所以,我们只须输入句柄名,再跟着输入"<<",然后接着写下一串用引号括起来的文本,就可以实现对文件的写入。如果我们想写入的是某个变量的值而不是带引号的文本,也只须像通常使用cout << 一样将变量传递给句柄对象,像这样:

SaveFile << variablename;

就可以了!

SaveFile.close(); —— 既然我们打开了一个流文件,那么当我们用完它之后,就必须关闭它。SaveFile是ofstream类的一个对象,而该类(ofstream)有一个用于关闭文件的成员函数,即close() 函数。因此,我们只要依次输入文件句柄名,点号和close(),就可以关闭该文件!

注意:一旦你关闭文件,在你重新打开它以前,就再不能对它进行访问。


以上就是一个可以写文件的最简单程序。的确很容易!不过,正如你即将在以后部分的教程中所看到的,还有更多的东西要学呢
(2):读取文件
(3):掌握输入/输出流



(2):读取文件
读取文件

你已经看到了应该如何写文件。现在,当我们已经得到cpp-home.txt文件时,我们将要读取它,并且将内容打印在屏幕上。

首先,我要指出的是,有很多种方法可以读取文件。以后我会向你们介绍所有的方法(就我所知的)。此刻,我先向你展示最佳的方法(我认为的)。

正如你已经熟悉的——我将首先给出一段程序代码,然后,我会详细地对它进行解释说明:

#include <fstream.h>

void main() //程序从这里开始

{

ifstream OpenFile("cpp-home.txt");

char ch;

while(!OpenFile.eof())

{

OpenFile.get(ch);

cout << ch;

}

OpenFile.close();

}

你想必已经了解首行的意义所在,而剩下的部分将由我为你解释。

ifstream OpenFile("cpp-home.txt") —— 我猜它对现在的你而言多少会熟悉些!ifstream表示"input file stream(输入文件流)"。在前一节的程序中,出现的则是ofstream,它的意义是"output file stream(输出文件流)"。前一节的程序是进行文件的写操作,这就是它用"output(输出)"来表示的原因。而本节的程序则是读取一个文件,这就是它用"input(输入)"来表示的原因。这一行剩下的代码于你而言应当是熟悉的了:OpenFile是ifstream类的一个对象,它将关联一个输入文件流;而用引号括住的内容,就是将要打开的文件的名称。

请注意:这里没有对要打开的文件是否存在进行测试!以后我将向你指出如何进行检测。

char ch; —— 声明一个字符数组(array of type char)。只是有一点要提醒你:这样的数组(arrays)只能存储一个ASCII字符。

while(!OpenFile.eof()) —— 如果已经到达文件末尾,eof( )函数将返回一个非零值。因此我们所设计的这个循环将一直持续,直至我们的文件操作到达文件末尾。这样我们就可以遍历整个文件,以便对它进行读取。

OpenFile.get(ch); —— OpenFile是类ifstream的一个对象。该类声明了一个名为get( )的成员函数。只要我们拥有该对象,我们自然就可以调用这个函数。get( )函数从相应的流文件中读出一个字符,并将其返回给变量。在本例中,get( )函数只带一个参数——用于存储所读取的字符的变量。所以,调用OpenFile.get(ch)后程序将会从OpenFile流中读取一个字符并存入变量ch中。

注意:如果你再次调用该函数,它将读取下一个字符,而不是原来的那一个!你过后将理解为什么会这样。

这就是我们要不断反复循环直至读操作到达文件尾的原因。每循环一次,我们将读出一个字符并将它保存在ch中。


cout << ch; —— 显示ch变量值,它保存了读取得到的字符。


File.close(); —— 我们打开了一个流式文件,就需要关闭它。使用close()函数即可将它关闭,这和前一节的一样!

注意:一旦你关闭了一个文件,在你重新打开它之前,你不能再对它进行访问。


大功告成了!我希望你能明白我的解释。当你编译并运行这个程序的时候,它应当会输出:

"Hello World, from www.cpp-home.com and Loobian!"


(3):掌握输入/输出流
掌握输入/输出流

在这一章里,我会提及一些有用的函数。我将为你演示如何打开一个可以同时进行读、写操作的文件;此外,我还将为你介绍其它打开文件的方法,以及如何判断打开操作是否成功。因此,请接着往下读!

到目前为止,我已为你所展示的只是单一的打开文件的途径:要么为读取而打开,要么为写入而打开。但文件还可以以其它方式打开。迄今,你应当已经认识了下面的方法:

ifstream OpenFile("cpp-home.txt");

噢,这可不是唯一的方法!正如以前所提到的,以上的代码创建一个类ifstream的对象,并将文件的名字传递给它的构造函数。但实际上,还存在有不少的重载的构造函数,它们可以接受不止一个的参数。同时,还有一个open()函数可以做同样的事情。下面是一个以上代码的示例,但它使用了open ()函数:

ifstream OpenFile;

OpenFile.open("cpp-home.txt");


你会问:它们之间有什么区别吗?哦,我曾做了不少测试,结论是没有区别!只不过如果你要创建一个文件句柄但不想立刻给它指定一个文件名,那么你可以使用open()函数过后进行指定。顺便再给出一个要使用open()函数的例子:如果你打开一个文件,然后关闭了它,又打算用同一个文件句柄打开另一个文件,这样一来,你将需要使用open()函数。

考虑以下的代码示例:

#include <fstream.h>

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(!T.eof())

{

T.get(ch);

cout << ch;

}

cout << endl << "--------" << endl;

}

void main()

{

ifstream T("file1.txt");

read(T);

T.close();

T.open("file2.txt");

read(T);

T.close();

}

据此,只要file1.txt和file2.txt并存储了文本内容,你将看到这些内容。

现在,该向你演示的是,文件名并不是你唯一可以向open()函数或者构造函数(其实都一样)传递的参数。下面是一个函数原型:

ifstream OpenFile(char *filename, int open_mode);

你应当知道filename表示文件的名称(一个字符串),而新出现的则是open_mode(打开模式)。open_mode的值用来定义以怎样的方式打开文件。下面是打开模式的列表:

名称 描述

ios::in 打开一个可读取文件

ios::out 打开一个可写入文件

ios::app 你写入的所有数据将被追加到文件的末尾,此方式使用ios::out

ios::ate 你写入的所有数据将被追加到文件的末尾,此方式不使用ios::out

ios::trunk 删除文件原来已存在的内容(清空文件)

ios::nocreate 如果要打开的文件并不存在,那么以此参数调用open()函数将无法进行。

ios::noreplace 如果要打开的文件已存在,试图用open()函数打开时将返回一个错误。

ios::binary 以二进制的形式打开一个文件。

实际上,以上的值都属于一个枚举类型的int常量。但为了让你的编程生涯不至于太痛苦,你可以像上表所见的那样使用那些名称。

下面是一个关于如何使用打开模式的例子:

#include <fstream.h>

void main()

{

ofstream SaveFile("file1.txt", ios::ate);

SaveFile << "That&#39;s new!\n";

SaveFile.close();

}


正如你在表中所看到的:使用ios::ate将会从文件的末尾开始执行写入。如果我没有使用它,原来的文件内容将会被重新写入的内容覆盖掉。不过既然我已经使用了它,那么我只会在原文件的末尾进行添加。所以,如果file1.txt原有的内容是这样:

Hi! This is test from www.cpp-home.com!

那么执行上面的代码后,程序将会为它添上"That&#39;s new!",因此它看起来将变成这样:

Hi! This is test from www.cpp-home.com!That&#39;s new!

假如你打算设置不止一个的打开模式标志,只须使用OR操作符或者是 | ,像这样:

ios::ate | ios::binary

我希望现在你已经明白"打开模式"是什么意思了!

现在,是时候向你展示一些真正有用的东西了!我敢打赌你现在还不知道应当怎样打开一个可以同时进行读取和写入操作的文件!下面就是实现的方法:

fstream File("cpp-home.txt",ios::in | ios::out);

实际上,这只是一个声明语句。我将在下面数行之后给你一个代码示例。但此时我首先想提及一些你应当知道的内容。

上面的代码创建了一个名为"File"的流式文件的句柄。如你所知,它是fstream类的一个对象。当使用fstream时,你应当指定 ios::in和ios::out作为文件的打开模式。这样,你就可以同时对文件进行读、写,而无须创建新的文件句柄。噢,当然,你也可以只进行读或者写的操作。那样的话,相应地你应当只使用ios::in或者只使用ios::out —— 要思考的问题是:如果你打算这么做,为什么你不分别用ifstream及ofstream来实现呢?

下面就先给出示例代码:

#include <fstream.h>

void main()
{

fstream File("test.txt",ios::in | ios::out);

File << "Hi!"; //将"Hi!"写入文件

static char str[10]; //当使用static时,数组会自动被初始化

//即是被清空为零

File.seekg(ios::beg); // 回到文件首部

// 此函数将在后面解释

File >> str;

cout << str << endl;



File.close();
}


OK,这儿又有一些新东西,所以我将逐行进行解释:

fstream File("test.txt", ios::in | ios::out); —— 此行创建一个fstream对象,执行时将会以读/写方式打开test.txt文件。这意味着你可以同时读取文件并写入数据。

File << "Hi!"; —— 我打赌你已经知道它的意思了。

static char str[10]; —— 这将创建一个容量为10的字符数组。我猜static对你而言或者有些陌生,如果这样就忽略它。这只不过会在创建数组的同时对其进行初始化。

File.seekg(ios::beg); —— OK,我要让你明白它究竟会做些什么,因此我将以一些有点儿离题、但挺重要的内容开始我的解释。

还记得它么:

while(!OpenFile.eof())

{

OpenFile.get(ch);

cout << ch;

}

你是不是曾经很想知道那背后真正执行了什么操作?不管是或不是,我都将为你解释。这是一个while型循环,它会一直反复,直至程序的操作到达文件的尾端。但这个循环如何知道是否已经到了文件末尾?嗯,当你读文件的时候,会有一个类似于"内置指针(inside-pointer)"的东西,它表明你读取(写入也一样)已经到了文件的哪个位置,就像记事本中的光标。而每当你调用OpenFile.get(ch)的时候,它会返回当前位置的字符,存储在ch变量中,并将这一内置指针向前移动一个字符。因此下次该函数再被调用时,它将会返回下一个字符。而这一过程将不断反复,直到读取到达文件尾。所以,让我们回到那行代码:函数seekg()将把内置指针定位到指定的位置(依你决定)。你可以使用:

ios::beg —— 可将它移动到文件首端

ios::end —— 可将它移动到文件末端

或者,你可以设定向前或向后跳转的字符数。例如,如果你要向定位到当前位置的5个字符以前,你应当写:

File.seekg(-5);

如果你想向后跳过40个字符,则应当写:

File.seekg(40);

同时,我必须指出,函数seekg()是被重载的,它也可以带两个参数。另一个版本是这样子的:

File.seekg(-5,ios::end);

在这个例子中,你将能够读到文件文本的最后4个字符,因为:

1)你先到达了末尾(ios::end)

2)你接着到达了末尾的前五个字符的位置(-5)

为什么你会读到4个字符而不是5个?噢,只须把最后一个看成是"丢掉了",因为文件最末端的"东西"既不是字符也不是空白符,那只是一个位置(译注:或许ios::end所"指"的根本已经超出了文件本身的范围,确切的说它是指向文件最后一个字符的下一个位置,有点类似STL中的各个容器的end 迭代点是指向最后一个元素的下一位置。这样设计可能是便于在循环中实现遍历)。

你现在可能想知道为什么我要使用到这个函数。呃,当我把"Hi"写进文件之后,内置指针将被设为指向其后面......也就是文件的末尾。因此我必须将内置指针设回文件起始处。这就是这个函数在此处的确切用途。

File >> str; —— 这也是新鲜的玩意儿!噢,我确信这行代码让你想起了cin >> .实际上,它们之间有着相当的关联。此行会从文件中读取一个单词,然后将它存入指定的数组变量中。

例如,如果文件中有这样的文本片断:

Hi! Do you know me?

使用File >> str,则只会将"Hi!"输出到str数组中。你应当已经注意到了,它实际上是将空格作为单词的分隔符进行读取的。

由于我存入文件中的只是单独一个"Hi!",我不需要写一个while循环,那会花费更多的时间来写代码。这就是我使用此方法的原因。顺便说一下,到目前为止,我所使用的读取文件的while循环中,程序读文件的方式是一个字符一个字符进行读取的。然而你也可以一个单词一个单词地进行读取,像这样:

char str[30]; // 每个单词的长度不能超过30个字符

while(!OpenFile.eof())

{

OpenFile >> str;

cout << str;

}



你也可以一行一行地进行读取,像这样:

char line[100]; // 每个整行将会陆续被存储在这里
while(!OpenFile.eof())
{

OpenFile.getline(line,100); // 100是数组的大小

cout << line << endl;
}


你现在可能想知道应当使用哪种方法。嗯,我建议你使用逐行读取的方式,或者是最初我提及的逐字符读取的方式。而逐词读取的方式并非一个好的方案,因为它不会读出新起一行这样的信息,所以如果你的文件中新起一行时,它将不会将那些内容新起一行进行显示,而是加在已经打印的文本后面。而使用 getline()或者get()都将会向你展现出文件的本来面目!

现在,我将向你介绍如何检测文件打开操作是否成功。实现上,好的方法少之又少,我将都会涉及它们。需要注意的是,出现"X"的时候,它实际可以以"o"、 "i"来代替,或者也可以什么都不是(那将是一个fstream对象)。

例1:最通常的作法

Xfstream File("cpp-home.txt");

if (!File)
{

cout << "Error opening the file! Aborting...\n";

exit(1);
}


例2:如果文件已经被创建,返回一个错误

ofstream File("unexisting.txt", ios::nocreate);

if(!File)

{

cout << "Error opening the file! Aborting...\n";

exit(1);

}

例3:使用fail()函数

ofstream File("filer.txt", ios::nocreate);

if(File.fail())

{

cout << "Error opening the file! Aborting...\n";

exit(1);

}


例3中的新出现的东西,是fail()函数。如果有任何输入/输出错误(不是在文件末尾)发生,它将返回非零值。

我也要讲一些我认为非常重要的内容!例如,如果你已经创建一个流文件对象,但你没有进行打开文件操作,像这样:

ifstream File; //也可以是一个ofstream

这样,我们就拥有一个文件句柄,但我们仍然没有打开文件。如果你打算迟些打开它,那么可以用open()函数来实现,我已经在本教程中将它介绍了。但如果在你的程序的某处,你可能需要知道当前的句柄是否关联了一个已经打开的文件,那么你可以用is_open()来进行检测。如果文件没有打开,它将返回0 (false);如果文件已经打开,它将返回1 (true)。例如:

ofstream File1;

File1.open("file1.txt");

cout << File1.is_open() << endl;


上面的代码将会返回1(译注:指File1.is_open()函数,下句同),因为我们已经打开了一个文件(在第二行)。而下面的代码则会返回0,这是由于我们没有打开文件,而只是创建了一个流文件句柄:

ofstream File1;

cout << File1.is_open() << endl;

好啦,这一章讲得够多啦。
(5):二进制文件的处理
二进制文件的处理

虽然有规则格式(formatted)的文本(到目前为止我所讨论的所有文件形式)非常有用,但有时候你需要用到无格式(unformatted)的文件——二进制文件。它们和你的可执行程序看起来一样,而与使用<<及>>操作符创建的文件则大不相同。get()函数与put()函数则赋予你读/写无规则格式文件的能力:要读取一个字节,你可以使用get()函数;要写入一个字节,则使用put ()函数。你应当回想起get()——我曾经使用过它。你可能会疑惑为什么当时我们使用它时,输出到屏幕的文件内容看起来是文本格式的?嗯,我猜这是因为我此前使用了<<及>>操作符。

译注:作者的所谓"规则格式文本(formatted text)"即我们平时所说的文本格式,而与之相对的"无格式文件(unformatted files)"即以存储各类数据或可执行代码的非文本格式文件。通常后者需要读入内存,在二进制层次进行解析,而前者则可以直接由预定好的< <及>>操作符进行读入/写出(当然,对后者也可以通过恰当地重载<<及>>操作符实现同样的功能,但这已经不是本系列的讨论范围了)。

get()函数与都各带一个参数:一个char型变量(译注:指get()函数)或一个字符(译注:指put()函数,当然此字符也可以以char型变量提供)。

假如你要读/写一整块的数据,那么你可以使用read()和write()函数。它们的原型如下:

istream &read(char *buf, streamsize num);

ostream &write(const char *buf, streamsize num);

对于read()函数,buf应当是一个字符数组,由文件读出的数据将被保存在这儿。对于write()函数,buf是一个字符数组,它用以存放你要写入文件的数据。对于这两个函数,num是一个数字,它指定你要从文件中读取/写入的字节数。

假如在读取数据时,在你读取"num"个字节之前就已经到达了文件的末尾,那么你可以通过调用gcount()函数来了解实际所读出的字节数。此函数会返回最后一次进行的对无格式文件的读入操作所实际读取的字节数。

在给出示例代码之前,我要补充的是,如果你要以二进制方式对文件进行读/写,那么你应当将ios::binary作为打开模式加入到文件打开的参数表中。

现在就让我向你展示示例代码,你会看到它是如何运作的。

示例1:使用get( )和put( )

#include <fstream.h>

void main()

{

fstream File("test_file.txt",ios::out | ios::in | ios::binary);

char ch;

ch=&#39;o&#39;;

File.put(ch); // 将ch的内容写入文件

File.seekg(ios::beg); // 定位至文件首部

File.get(ch); // 读出一个字符

cout << ch << endl; // 将其显示在屏幕上

File.close();

}

示例2:使用read( )和write( )

#include <fstream.h>

#include <string.h>

void main()

{

fstream File("test_file.txt",ios::out | ios::in | ios::binary);

char arr[13];

strcpy(arr,"Hello World!"); //将Hello World!存入数组

File.write(arr,5); // 将前5个字符——"Hello"写入文件

File.seekg(ios::beg); // 定位至文件首部

static char read_array[10]; // 在此我将打算读出些数据

File.read(read_array,3); // 读出前三个字符——"Hel"

cout << read_array << endl; // 将它们输出

File.close();

}
(6):一些有用的函数
tellg() ——返回一个int型数值,它表示"内置指针"的当前位置。此函数仅当你在读取一个文件时有效。例如:
#include <fstream.h>

void main()
{
// 假如我们已经在test_file.txt中存有了"Hello"的内容
ifstream File("test_file.txt");

char arr[10];

File.read(arr,10);

// 由于Hello占5个字符,因此这里将返回5
cout << File.tellg() << endl;

File.close();
}

tellp() —— 与tellg()有同样的功能,但它用于写文件时。总而言之:当我们读取一个文件,并要知道内置指针的当前位置时,应该使用tellg();当我们写入一个文件,并要知道内置指针的当前位置时,应该使用tellp(). 由于此函数的用法与tellg()完全一样,我就不给出示例代码了。

seekp() —— 还记得seekg()么?当我在读取一个文件,并想到达文件中某个特定位置时,就曾使用过它。seekp()亦如此,只不过它用于写入一个文件的时候。例如,假如我在进行文件读写,而要定位到当前位置的三个字符之前,则需调用FileHandle.seekg(-3). 但如果我是在写入一个文件,并且比如我要重写后5个字符的内容,我就必须往回跳转5个字符,因而,我应该使用FileHandle.seekp(-5) .

ignore() —— 使用于读取文件之时。如果你想略过一定数量的字符,只需使用此函数。实际上,你也可以使用seekg()来代替,然而使用ignore()有一个优点—— 你可以指定一个特定"界限规则(delimiter rule)",同样使得ignore()在指定的位置停下。函数原型如下:

istream& ignore( int nCount, delimiter );

nCount表示要略过的字符数量,而delimiter —— 与它的名称有着同样的含义:假如你想在文件末尾停下,则可使用EOF值传入,这样一来此函数就等同于seekg();但该参数还可以使用其他值,例如‘\ n&#39;这样可以在换行的同时定位在新行处。下面是示例:
#include <fstream.h>

void main()
{
// 假设test_file.txt中已经存有"Hello World"这一内容
ifstream File("test_file.txt");

static char arr[10];

// 假如一直没有遇到字符"l",则向前定位直到跳过6个字符
// 而如果期间遇到"l",则停止向前,定位在该处
File.ignore(6,&#39;l&#39;);

File.read(arr,10);

cout << arr << endl; // 它将显示"lo World!"

File.close();

}

getline() —— 虽然前面的章节中我曾提到过这个函数,但还有一些内容我们未曾涉及:此函数不但可用于逐行读取,而且它还可以设为遇到某个特定字符后停止读取。下面给出传递这一参数的方法:

getline(array,array_size,delim);

以下为示例代码:

#include <fstream.h>

void main()
{
// 假设test_file.txt中已经存有"Hello World"这一内容
ifstream File("test_file.txt");

static char arr[10];

/* 读取,直到满足下面的条件之一:
1)已经读取10个字符
2)遇到字母"o"
3)出现新一行
*/
File.getline(arr,10,&#39;o&#39;);

cout << arr << endl; // 将显示"Hell"
File.close();
}

peek() —— 此函数将返回输入流文件的下一个字符,但它不移动内置指针。我想你该记得,像get()这样的函数也返回输入流文件的下一个字符,而与此同时它将移动内置指针。所以当你再次调用get()函数的时候,它会返回再下一个字符,而非前面那个。哦,使用peek()也会返回字符,但它不会移动"光标"。所以,假如你连续两次调用peek()函数,它会返回同一个字符。考虑以下代码:

#include <fstream.h>

void main()
{
// 假设test_file.txt中已经存有"Hello World"这一内容
ifstream File("test_file.txt");

char ch;

File.get(ch);
cout << ch << endl; // 将显示"H"

cout << char(File.peek()) << endl; //将显示"e"
cout << char(File.peek()) << endl; //将再次显示"e"

File.get(ch);
cout << ch << endl; // 还是显示"e"

File.close();

}

顺便说一下,我忘了讲——peek()函数实质上返回的是字符的ASCII码,而非字符本身。因此,假如你想看到字符本身,你得像我在示例中做的那样进行调用(译注:即要转为char类型)。

_unlink() —— 删除一个文件。假如你要使用此函数,需要在你的程序中包含io.h头文件。下面是示例代码:

#include <fstream.h>
#include <io.h>

void main()
{
ofstream File;

File.open("delete_test.txt"); //创建一个文件
File.close();

_unlink("delete_test.txt"); // 删除这个文件

// 试图打开此文件,但假如它已不存在
// 函数将返回一个ios::failbit错误值
File.open("delete_test.txt",ios::nocreate);

// 验证它是否返回该值
if(File.rdstate() == ios::failbit)
cout << "Error...!\n"; // 耶,成功了

File.close();

}

putback() —— 此函数将返回最后一个所读取字符,同时将内置指针移动-1个字符。换言之,如果你使用get()来读取一个字符后再使用putback(),它将为你返回同一个字符,然而同时会将内置指针移动-1个字符,所以你再次使用get()时,它还是会为你返回同样的字符。下面是示例代码:

#include <fstream.h>

void main()
{
// test_file.txt应包含内容"Hello World"
ifstream File("test_file.txt");

char ch;

File.get(ch);

cout << ch << endl; // 将显示"H"

File.putback(ch);
cout << ch << endl; // 仍将显示"H"

File.get(ch);
cout << ch << endl; // 再一次显示"H"

File.close();
}

flush() —— 在处理输出流文件的时候,你所存入的数据实际上并非立刻写入文件,而是先放入一个缓冲区中,直到该缓冲区放满数据之后,这些数据才被存入真正的文件中(在你的磁盘上)。旋即缓冲区会被清空,再重新进行下一轮写入。
但假如你想在缓冲区写满之前就将其中的数据写入磁盘,则使用flush()函数。只须像这样进行调用:FileHandle.flush(),这样缓冲区内的数据将会写入实际的物理文件,而后缓冲区被清空。
再补充一点(高阶的)内容:flush()函数会调用与相应流缓冲(streambuf)相联系的sync()函数(出自MSDN)。

结语

嗯,我希望你现在可以实现你的文件输入/输出程序了。我已经将自己所知的内容都涉及到,我想它们比你所需要的还要多。即使如此,还是会有一些内容我没有提及的......不过我想你或许都不会使用到那些方面的内容。因此,如果你还需要了解更多关于某些特定主题的高阶的理论,可以在互联网上搜索,例如,可以尝试一下google.com,但你可别来问我!我不对任何询问我关于如何实现某个程序此类问题的邮件作答复。
假如你喜欢这个系列的教程,或者相反,我都会非常高兴能看到你的意见。所以请随意地在网上联系我:loobian@cpp-home.com
想获取更多的C++教程,请访问:www.cpp-home.com


- 作者: ding6222 2005年01月15日, 星期六 12:53  回复(0) |  引用(0) 加入博采
c++入门学习笔记指针篇
指针优点:
1。为函数提供修改调用变元的手段;
2。支持C++动态分配子程序
3。可以改善某些子程序的效率
4。为动态数据结构(如二叉树、链表)提供支持

注:指针为程序引入了一层间接性,可以操控指针而不直接操控对象。
1。可操控指针内含的地址也可操控指针所指的对象
2。指针可能并不指向任何对象,写*pi时,可能会使程序在执行期错误,如寻址到某个对象,则提领操作,不指向任何对象,会出错,所以在提领前先确定它的确指向某对象.
一个未指向任何对象的指针,内含地址为0,有时称为null指针,assert (p != 0)可检测是否分配成功。也可用if (pi),只有在pi含非零值时,才为true.

一、定义:
为存放内存地址的变量。
诠释:
指针为一数据类型也有自己的地址。占用四个字节的存储空间
int * p: &p返回的是指针p的地址,而不是所指变量的地址
地址:一般指内存中另一变量的位置

二、指针变量:
type * name 声明时必须确保它的类型与要指向的对象类型兼容
const 是"最靠近"为原则
指向整数常量的指针:const int * p;它所指向的值只读不能被修改 *p = 4(错误),p = 5(正确)
指向一个整数的常量指针:int * const p;不允许修改指针变量的值,*p = 5 (正确),p = 5 (错误)

三、指针操作符:
&(取址运算符):一元操作符,只作用于一个操作数,返回操作数的地址
*(提领操作):一元操作符,是&的补操作,返回其操作数所指变量的值

四、指针赋值及转换:
同类型直接赋值,异类型要进行转换。
强制转换:可以把表达式结果硬性转换为指定类型
char * p;(int *)p 把p强制转换为int型,记住转换过程中要注意两个类型的大小,大转小时可能会有数据丢失(如int到double)
涉及void *的:
c 中void *类型可赋值给任何类型的指针,反之亦然
c++ 中都需要强制转换
void * 可似为无穷大能接纳任何类型赋值,反之不行int * p =9;void * t= p(正确);p=t(错误)

不涉及void *的都要强制转换

五、指针的算术操作
和整数的加法,减法,自身的增量、减量
指针增量后指向下一个与指针基类同型的元素,增减单位是所指类型的长度。

六、其他说明:
1。指针和数组:
不带下标的数组名返回数组的起始地址,即数组首元素的地址,所以对数组的访问可有两种方式:数组下标和指针算术
2。函数指针:
函数具有可赋给指针的物理内存地址,一个函数地址也为该函数的进入点,也是调用函数的地址
3。多级指针地址 **p

七、动态内存分配
定义:是程序在运行中取得内存的方法。是从堆(heap)--系统的自由内存区-取得内存
运算符:
new(c中的malloc):自动建立一个具有合适大小的对象,返回具有正确类型的指针,如分配不成功,返回一个空指针0,且可自动调用构造函数。
char * p = new char(&#39;t&#39;);
delete(c中的free):delect p;
释放数组对象时要使用方括号delete [] p;

八、与引用的区别
&引用运算符:
1。引用只是变量的别名,而不是指向变量的指针(区别于取址运算符"&")不占内存空间,对变量引用的改变其相应的变量也会改变。
2。不能对引用使用指针间接运算符"*"进行复引用操作
3。引用必须在声明时初始化 int &c = count;(c是count的别名)

九、注意:
在每次使用指针前,都应该初始化。以防止指针指向空对象。

应用举例(pointer.cpp)
编译环境:Window2000 Vc6.0
#include <string>
#include <iostream>
using namespace std;

void main()
{
//int * p =1, 不对,整型常量不能转换为整型指针,char * t =0 可以
//指针运算符&返回操作数的地址,此处&p,&q是p,q的地址
//要返回得到指向的地址要么正接用p,q 要么用&(*p),&(*q),指针也是
//是一种数据类型也有自己的内存地址为4个字节,8位
int * q , * p;
int x =1 ,y = 2;
q = &x;
p = &y;
cout << "p" << &p << " "<< &(*p)
<< " " << p <<" " << *p << endl;
cout << "q" << &q << " " << &(*q)
<< " "<< q<<" "<< *q<< endl;

//指针赋值,整个指针包含的地址、指向的对象都改变了
int * t;
t = q;
q = p;
p = t;
cout << "p" << p << " "<< *p << endl;
cout << "q" << q << " " << *q << endl;

//指针所指对象的赋值操作,地址不变
q = &x; //1
p = &y; //2
cout << "p" << p << " "<< *p << endl;
cout << "q" << q << " " << *q << endl;

//强制类型转换
//double *l;
//l = (double*)*q; // q的值赋给临时变量 *t=1

*t = *q; // q的值赋给临时变量 *t=1
cout << *t <<endl;
*q = *p; // q的值给q,*q=2
cout << *q <<endl;
//??*p = *t; //为什么此处*p值没有改变
*p = *t;
cout << *t <<endl;
cout << "p" << p << " "<< *p << endl;
cout << "q" << q << " " << *q << endl;

//引用的使用
int count = 1;
int &c = count; //声明c为count的引用,c只是count的别名,不占实际内存空间
cout << "引用";
cout << c << count << endl;
//引用变量在声明时要初始化
//int &t; (错误)
//t = count ;

//不能用指针间接运算符复引用一引用,引用只是一变量的别名
//它不占地址空间
//cout << *c << endl;

int iF = 10;
const int * ciS = 0; //指向整数常量的指针,指针最好都进行初始化
int * iT = &iF;
//*ciS = 100;(错误),*ciS为常量
ciS = iT;
cout << ciS << " "<< *ciS <<endl;

int * const icS = &iF; //指向整数的常量指针
*icS = 10;
icS = iT;
cout << icS << " " << *icS << endl;
}


- 作者: ding6222 2005年01月14日, 星期五 22:07  回复(2) |  引用(0) 加入博采
变量的定义与声明的区别
我们在程序设计中,时时刻刻都用到变量的定义和变量的声明,可有些时候我们对这个概念不是很清楚,知道它是怎么用,但却不知是怎么一会事,下面我就简单的把他们的区别介绍如下:(望我的指点对你受益)
变量的声明有两种情况:

一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。

另一种是不需要建立存储空间的 例如:extern int a 其中 变量a是在别的文件中定义的.前者是"定义性声明 (defining declaration)"或者称为"定义(definition)",而后者是"引用性声明 (referncing declaration)" 从广义的角度来讲 声明中包含着定义,但是并非所有的声明都是定义,例如:int a 它既是声明,同时又是定义。然而对于 extern a 来讲 它只是声明不是定义。一般的情况下我们常常这样叙述,把建立空间的声明称之为"定义",而把不需要建立存储空间称之为"声明"。很明显我们在这里指的生命是范围比较窄的,也就是说非定义性质的声明 例如:在主函数中

int main()
{
extern int A; //这是个声明而不是定义,声明A是一个已经定义了的外部变量
//注意:声明外部变量时可以把变量类型去掉如:extern A;
dosth(); //执行函数
}
int A; //是定义,定义了A为整型的外部变量

外部变量的"定义"与外部变量的"声明"是不相同的,外部变量的定义只能有一次,它的位置是在所有函数之外,而同一个文件中的外部变量声明可以是多次的,它可以在函数之内(哪个函数要用就在那个函数中声明)也可以在函数之外(在外部变量的定义点之前)。系统会根据外部变量的定义(而不是根据外部变量的声明)分配存储空间的。对于外部变量来讲,初始化只能是在"定义"中进行,而不是在"声明"中 。所谓的"声明",其作用,是声明该变量是一个已在后面定义过的外部变量,仅仅是在为了"提前"引用该变量而作的"声明"而已。extern 只作声明,不作任何定义 。

用static来声明一个变量的作用有二:(1)对于局部变量用static声明,则是为该变量分配的空间在整个程序的执行期内都始终存在(2)外部变量用static来声明,则该变量的作用只限于本文件模块
看贴是学习,回帖是礼貌.看到好贴,顶一下哦.你的回帖是我的动力支持一下我们,把我们C3P论坛告诉你的同学朋友:
http://www.CadCaeCam.comAutocad ARX, Catia CAA&VBA, Ansys, 医学有限元分析 联系HuangSteve@sohu.com

个人空间http://www.cadcaecam.com/home.php?mod=space&uid=21
 
回复

使用道具举报

  • 显身卡
 
HuangSteve
HuangSteve当前离线
威望
45 点
C3P币
59030 元
贡献值
2318 点
推广邀请能量
5815 焦耳
最后登录
2012-5-1
注册时间
2000-7-9
帖子
42885
精华
39
积分
59030
阅读权限
200
UID
21
QQ阿里旺旺查看详细资料 IP卡 狗仔卡
 
2
发表于 2008-3-23 09:47:52|只看该作者
C++中的文件输入/输出:一些有用的函数


原作:Ilia Yordanov, loobian@cpp-home.com




tellg() ——返回一个int型数值,它表示“内置指针”的当前位置。此函数仅当你在读取一个文件时有效。例如:
#include <fstream.h>

void main()
{
// 假如我们已经在test_file.txt中存有了“Hello”的内容
ifstream File("test_file.txt");

char arr[10];

File.read(arr,10);

// 由于Hello占5个字符,因此这里将返回5
cout << File.tellg() << endl;

File.close();
}

tellp() —— 与tellg()有同样的功能,但它用于写文件时。总而言之:当我们读取一个文件,并要知道内置指针的当前位置时,应该使用tellg();当我们写入一个文件,并要知道内置指针的当前位置时,应该使用tellp(). 由于此函数的用法与tellg()完全一样,我就不给出示例代码了。

seekp() —— 还记得seekg()么?当我在读取一个文件,并想到达文件中某个特定位置时,就曾使用过它。seekp()亦如此,只不过它用于写入一个文件的时候。例如,假如我在进行文件读写,而要定位到当前位置的三个字符之前,则需调用FileHandle.seekg(-3). 但如果我是在写入一个文件,并且比如我要重写后5个字符的内容,我就必须往回跳转5个字符,因而,我应该使用FileHandle.seekp(-5) .

ignore() —— 使用于读取文件之时。如果你想略过一定数量的字符,只需使用此函数。实际上,你也可以使用seekg()来代替,然而使用ignore()有一个优点——你可以指定一个特定“界限规则(delimiter rule)”,同样使得ignore()在指定的位置停下。函数原型如下:

istream& ignore( int nCount, delimiter );

nCount表示要略过的字符数量,而delimiter —— 与它的名称有着同样的含义:假如你想在文件末尾停下,则可使用EOF值传入,这样一来此函数就等同于seekg();但该参数还可以使用其他值,例如‘\n’这样可以在换行的同时定位在新行处。下面是示例:
#include <fstream.h>

void main()
{
// 假设test_file.txt中已经存有"Hello World"这一内容
ifstream File("test_file.txt");

static char arr[10];

// 假如一直没有遇到字符"l",则向前定位直到跳过6个字符
// 而如果期间遇到"l",则停止向前,定位在该处
File.ignore(6,&#39;&#39;l&#39;&#39;);

File.read(arr,10);

cout << arr << endl; // 它将显示"lo World!"

File.close();

}

getline() —— 虽然前面的章节中我曾提到过这个函数,但还有一些内容我们未曾涉及:此函数不但可用于逐行读取,而且它还可以设为遇到某个特定字符后停止读取。下面给出传递这一参数的方法:

getline(array,array_size,delim);

以下为示例代码:

#include <fstream.h>

void main()
{
// 假设test_file.txt中已经存有"Hello World"这一内容
ifstream File("test_file.txt");

static char arr[10];

/* 读取,直到满足下面的条件之一:
1)已经读取10个字符
2)遇到字母"o"
3)出现新一行
*/
File.getline(arr,10,&#39;&#39;o&#39;&#39;);

cout << arr << endl; // 将显示"Hell"
File.close();
}

peek() —— 此函数将返回输入流文件的下一个字符,但它不移动内置指针。我想你该记得,像get()这样的函数也返回输入流文件的下一个字符,而与此同时它将移动内置指针。所以当你再次调用get()函数的时候,它会返回再下一个字符,而非前面那个。哦,使用peek()也会返回字符,但它不会移动“光标”。所以,假如你连续两次调用peek()函数,它会返回同一个字符。考虑以下代码:

#include <fstream.h>

void main()
{
// 假设test_file.txt中已经存有"Hello World"这一内容
ifstream File("test_file.txt");

char ch;

File.get(ch);
cout << ch << endl; // 将显示"H"

cout << char(File.peek()) << endl; //将显示"e"
cout << char(File.peek()) << endl; //将再次显示"e"

File.get(ch);
cout << ch << endl; // 还是显示"e"

File.close();

}

顺便说一下,我忘了讲——peek()函数实质上返回的是字符的ASCII码,而非字符本身。因此,假如你想看到字符本身,你得像我在示例中做的那样进行调用(译注:即要转为char类型)。

_unlink() —— 删除一个文件。假如你要使用此函数,需要在你的程序中包含io.h头文件。下面是示例代码:

#include <fstream.h>
#include <io.h>

void main()
{
ofstream File;

File.open("delete_test.txt"); //创建一个文件
File.close();

_unlink("delete_test.txt"); // 删除这个文件

// 试图打开此文件,但假如它已不存在
// 函数将返回一个ios::failbit错误值
File.open("delete_test.txt",ios::nocreate);

// 验证它是否返回该值
if(File.rdstate() == ios::failbit)
cout << "Error...!\n"; // 耶,成功了

File.close();

}

putback() —— 此函数将返回最后一个所读取字符,同时将内置指针移动-1个字符。换言之,如果你使用get()来读取一个字符后再使用putback(),它将为你返回同一个字符,然而同时会将内置指针移动-1个字符,所以你再次使用get()时,它还是会为你返回同样的字符。下面是示例代码:

#include <fstream.h>

void main()
{
// test_file.txt应包含内容"Hello World"
ifstream File("test_file.txt");

char ch;

File.get(ch);

cout << ch << endl; // 将显示"H"

File.putback(ch);
cout << ch << endl; // 仍将显示"H"

File.get(ch);
cout << ch << endl; // 再一次显示"H"

File.close();
}

flush() —— 在处理输出流文件的时候,你所存入的数据实际上并非立刻写入文件,而是先放入一个缓冲区中,直到该缓冲区放满数据之后,这些数据才被存入真正的文件中(在你的磁盘上)。旋即缓冲区会被清空,再重新进行下一轮写入。
但假如你想在缓冲区写满之前就将其中的数据写入磁盘,则使用flush()函数。只须像这样进行调用:FileHandle.flush(),这样缓冲区内的数据将会写入实际的物理文件,而后缓冲区被清空。
再补充一点(高阶的)内容:flush()函数会调用与相应流缓冲(streambuf)相联系的sync()函数(出自MSDN)。
看贴是学习,回帖是礼貌.看到好贴,顶一下哦.你的回帖是我的动力支持一下我们,把我们C3P论坛告诉你的同学朋友:
http://www.CadCaeCam.comAutocad ARX, Catia CAA&VBA, Ansys, 医学有限元分析 联系HuangSteve@sohu.com

个人空间http://www.cadcaecam.com/home.php?mod=space&uid=21
 
回复

使用道具举报

  • 显身卡
  
HuangSteve
HuangSteve当前离线
威望
45 点
C3P币
59030 元
贡献值
2318 点
推广邀请能量
5815 焦耳
最后登录
2012-5-1
注册时间
2000-7-9
帖子
42885
精华
39
积分
59030
阅读权限
200
UID
21
QQ阿里旺旺查看详细资料 IP卡 狗仔卡
 
3
发表于 2008-3-23 09:40:15|只看该作者|倒序浏览
C++ 通过以下几个类支持文件的输入输出:

ofstream: 写操作(输出)的文件类 (由ostream引申而来)
ifstream: 读操作(输入)的文件类(由istream引申而来)
fstream: 可同时读写操作的文件类 (由iostream引申而来)

打开文件(Open a file)
对这些类的一个对象所做的第一个操作通常就是将它和一个真正的文件联系起来,也就是说打开一个文件。被打开的文件在程序中由一个流对象(stream object)来表示 (这些类的一个实例) ,而对这个流对象所做的任何输入输出操作实际就是对该文件所做的操作。

要通过一个流对象打开一个文件,我们使用它的成员函数open():

void open (const char * filename, openmode mode);这里filename 是一个字符串,代表要打开的文件名,mode 是以下标志符的一个组合:

ios::in 为输入(读)而打开文件
ios::out 为输出(写)而打开文件
ios::ate 初始位置:文件尾
ios::app 所有输出附加在文件末尾
ios::trunc 如果文件已存在则先删除该文件
ios::binary 二进制方式

这些标识符可以被组合使用,中间以”或”操作符(|)间隔。例如,如果我们想要以二进制方式打开文件”example.bin” 来写入一些数据,我们可以通过以下方式调用成员函数open()来实现:

ofstream file;
file.open ("example.bin", ios::out | ios::app | ios::binary); ofstream, ifstream 和 fstream所有这些类的成员函数open 都包含了一个默认打开文件的方式,这三个类的默认方式各不相同:

类 参数的默认方式
ofstream ios::out | ios::trunc
ifstream ios::in
fstream ios::in | ios::out

只有当函数被调用时没有声明方式反 a3b ?数的情况下,默认值才会被采用。如果函数被调用时声明了任何参数,默认值将被完全改写,而不会与调用参数组合。

由于对类ofstream, ifstream 和 fstream 的对象所进行的第一个操作通常都是打开文件,这些类都有一个构造函数可以直接调用open 函数,并拥有同样的参数。这样,我们就可以通过以下方式进行与上面同样的定义对象和打开文件的操作:

ofstream file ("example.bin", ios::out | ios::app | ios::binary);两种打开文件的方式都是正确的。

你可以通过调用成员函数is_open()来检查一个文件是否已经被顺利的打开了:

bool is_open();它返回一个布尔(bool)值,为真(true)代表文件已经被顺利打开,假( false )则相反。

关闭文件(Closing a file)
当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。关闭文件需要调用成员函数close(),它负责将缓存中的数据排放出来并关闭文件。它的格式很简单:

void close ();这个函数一旦被调用,原先的流对象(stream object)就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程(process)所有访问了。

为防止流对象被销毁时还联系着打开的文件,析构函数(destructor)将会自动调用关闭函数close。

文本文件(Text mode files)
类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引申而来的。这就是为什么 fstream 的对象可以使用其父类的成员来访问数据。

一般来说,我们将使用这些类与同控制台(console)交互同样的成员函数(cin 和 cout)来进行输入输出。如下面的例题所示,我们使用重载的插入操作符<<:

// writing on a text file
#include <fiostream.h>int main () {
ofstream examplefile (”example.txt”);
if (examplefile.is_open()) {
examplefile << “This is a line.\n”;
examplefile << “This is another line.\n”;
examplefile.close();
}
return 0;
} file example.txt
This is a line.
This is another line.

从文件中读入数据也可以用与 cin的使用同样的方法:

// reading a text file
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>int main () {
char buffer[256];
ifstream examplefile (”example.txt”);
if (! examplefile.is_open())
{ cout << “Error opening file”; exit (1); }
while (! examplefile.eof() ) {
examplefile.getline (buffer,100);
cout << buffer << endl;
}
return 0;
} This is a line.
This is another line.

上面的例子读入一个文本文件的内容,然后将它打印到屏幕上。注意我们使用了一个新的成员函数叫做eof ,它是ifstream 从类 ios 中继承过来的,当到达文件末尾时返回true 。

状态标志符的验证(Verification of state flags)
除了eof()以外,还有一些验证流的状态的成员函数(所有都返回bool型返回值):

bad()如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。
fail()除了与bad() 同样的情况下会返回 true 以外,加上格式错误时也返回true ,例如当想要读入一个整数,而获得了一个字母的时候。
eof()如果读文件到达文件末尾,返回true。
good()这是最通用的:如果调用以上任何一个函数返回true 的话,此函数返回 false 。
要想重置以上成员函数所检查的状态标志,你可以使用成员函数clear(),没有参数。

获得和设置流指针(get and put stream pointers)
所有输入/输出流对象(i/o streams objects)都有至少一个流指针:

ifstream, 类似istream, 有一个被称为get pointer的指针,指向下一个将被读取的元素。
ofstream, 类似 ostream, 有一个指针 put pointer ,指向写入下一个元素的位置。
fstream, 类似 iostream, 同时继承了get 和 put
我们可以通过使用以下成员函数来读出或配置这些指向流中读写位置的流指针:

tellg() 和 tellp()这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++ 标准) ,就是一个整数,代表当前get 流指针的位置 (用tellg) 或 put 流指针的位置(用tellp).
seekg() 和seekp()这对函数分别用来改变流指针get 和put的位置。两个函数都被重载为两种不同的原型:
seekg ( pos_type position );
seekp ( pos_type position );

使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。

seekg ( off_type offset, seekdir direction );
seekp ( off_type offset, seekdir direction );

使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。它可以是:

ios::beg 从流开始位置计算的位移
ios::cur 从流指针当前位置开始计算的位移
ios::end 从流末尾处开始计算的位移

流 指针 get 和 put 的值对文本文件(text file)和二进制文件(binary file)的计算方法都是不同的,因为文本模式的文件中某些特殊字符可能被修改。由于这个原因,建议对以文本文件模式打开的文件总是使用seekg 和 seekp的第一种原型,而且不要对tellg 或 tellp 的返回值进行修改。对二进制文件,你可以任意使用这些函数,应该不会有任何意外的行为产生。

以下例子使用这些函数来获得一个二进制文件的大小:

// obtaining file size
#include <iostream.h>
#include <fstream.h>const char * filename = “example.txt”;int main () {
long l,m;
ifstream file (filename, ios::in|ios::binary);
l = file.tellg();
file.seekg (0, ios::end);
m = file.tellg();
file.close();
cout << “size of ” << filename;
cout << ” is ” << (m-l) << ” bytes.\n”;
return 0;
} size of example.txt
is 40 bytes.

二进制文件(Binary files)
在二进制文件中,使用<< 和>>,以及函数(如getline)来操作符输入和输出数据,没有什么实际意义,虽然它们是符合语法的。

文 件流包括两个为顺序读写数据特殊设计的成员函数:write 和 read。第一个函数 (write) 是ostream 的一个成员函数,都是被ofstream所继承。而read 是istream 的一个成员函数,被ifstream 所继承。类 fstream 的对象同时拥有这两个函数。它们的原型是:

write ( char * buffer, streamsize size );
read ( char * buffer, streamsize size );

这里 buffer 是一块内存的地址,用来存储或读出数据。参数size 是一个整数值,表示要从缓存(buffer)中读出或写入的字符数。

// reading binary file
#include <iostream>
#include <fstream.h>const char * filename = “example.txt”;int main () {
char * buffer;
long size;
ifstream file (filename, ios::in|ios::binary|ios::ate);
size = file.tellg();
file.seekg (0, ios::beg);
buffer = new char [size];
file.read (buffer, size);
file.close();cout << “the complete file is in a buffer”;delete[] buffer;
return 0;
} The complete file
is in a buffer

缓存和同步(Buffers and Synchronization)
当 我们对文件流进行操作的时候,它们与一个streambuf 类型的缓存(buffer)联系在一起。这个缓存(buffer)实际是一块内存空间,作为流(stream)和物理文件的媒介。例如,对于一个输出流, 每次成员函数put (写一个单个字符)被调用,这个字符不是直接被写入该输出流所对应的物理文件中的,而是首先被插入到该流的缓存(buffer)中。

当缓存被排放出来(flush)时,它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话),或者简单的被抹掉(如果是一个输入流的话)。这个过程称为同步(synchronization),它会在以下任一情况下发生:

当文件被关闭时: 在文件被关闭之前,所有还没有被完全写出或读取的缓存都将被同步。
当缓存buffer 满时:缓存Buffers 有一定的空间限制。当缓存满时,它会被自动同步。
控制符明确指明:当遇到流中某些特定的控制符时,同步会发生。这些控制符包括:flush 和endl。
明确调用函数sync(): 调用成员函数sync() (无参数)可以引发立即同步。这个函数返回一个int 值,等于-1 表示流没有联系的缓存或操作失败。
原创粉丝点击