详解C++编程中的文件流与字符串流

C++文件流类与文件流对象
文件流是以外存文件为输入输出对象的数据流。输出文件流是从内存流向外存文件的数据,输入文件流是从外存文件流向内存的数据。每一个文件流都有一个内存缓冲区与之对应。

请区分文件流与文件的概念,不用误以为文件流是由若干个文件组成的流。文件流本身不是文件,而只是以文件为输入输出对象的流。若要对磁盘文件输入输出,就必须通过文件流来实现。

在C++的I/O类库中定义了几种文件类,专门用于对磁盘文件的输入输出操作。
除了标准输入输出流类istream、ostream和iostream类外,还有3个用于文件操作的文件类:

  1. ifstream类,它是从istream类派生的,用来支持从磁盘文件的输入。
  2. ofstream类,它是从ostream类派生的,用来支持向磁盘文件的输出。
  3. fstream类,它是从iostream类派生的,用来支持对磁盘文件的输入输出。

要以磁盘文件为对象进行输入输出,必须定义一个文件流类的对象,通过文件流对象将数据从内存输出到磁盘文件,或者通过文件流对象从磁盘文件将数据输入到内存。

其实在用标准设备为对象的输入输出中,也是要定义流对象的,如cin、cout就是流对象,C++是通过流对象进行输入输出的。由于cin、cout已在iostream.h中事先定义,所以用户不需自己定义。在用磁盘文件时,由于情况各异,无法事先统一定义,必须由用户自己定义。此外,对磁盘文件的操作是通过文件流对象(而不是cin和cout)实现的。文件流对象是用文件流类定义的,而不是用istream和ostream类来定义的。可以用下面的方法建立一个输出文件流对象:

  ofstream outfile;

如同在头文件iostream中定义了流对象cout —样,现在在程序中定义了outfile为 ofstream类(输出文件流类)的对象。但是有一个问埋还未解决:在定义 cout 时已将它和标准输出设备(显示器)建立关联,而现在虽然建立了一个输出文件流对象,但是还未指定它向哪一个磁盘文件输出,需要在使用时加以指定。

C++对字符串流的读写
文件流是以外存文件为输入输出对象的数据流,字符串流不是以外存文件为输入输出的对象,而以内存中用户定义的字符数组(字符串)为输入输出的对象,即将数据输出到内存中的字符数组,或者从字符数组(字符串)将数据读入。字符串流也称为内存流。

字符串流也有相应的缓冲区,开始时流缓冲区是空的。如果向字符数组存入数据,随着向流插入数据,流缓冲区中的数据不断增加,待缓冲区满了(或遇换行符),一起存入字符数组。如果是从字符数组读数据,先将字符数组中的数据送到流缓冲区,然后从缓冲区中提取数据赋给有关变量。

在字符数组中可以存放字符,也可以存放整数、浮点数以及其他类型的数据。在向字符数组存入数据之前,要先将数据从二进制形式转换为ASCII代码,然后存放在缓冲区, 再从缓冲区送到字符数组。从字符数组读数据时,先将字符数组中的数据送到缓冲区,在赋给变量前要先将ASCII代码转换为二进制形式。总之,流缓冲区中的数据格式与字符数组相同。这种情况与以标准设备(键盘和显示器)为对象的输入输出是类似的,键盘和显示器都是按字符形式输入输出的设备,内存中的数据在输出到显示器之前,先要转换为 ASCII码形式,并送到输出缓冲区中。从键盘输入的数据以ASCII码形式输入到输入缓冲区,在赋给变量前转换为相应变量类型的二进制形式,然后赋给变量。对于字符串流的输入输出的情况,如不清楚,可以从对标准设备的输入输出中得到启发。

文件流类有ifstream,ofstream和fstream,而字符串流类有istrstream,ostrstream和strstream。文件流类和字符串流类都是ostream,istream和iostream类的派生类,因此对它们的操作方法是基本相同的。向内存中的一个字符数组写数据就如同向文件写数据一样,但有3点不同:
输出时数据不是流向外存文件,而是流向内存中的一个存储空间。输入时从内存中的存储空间读取数据。在严格的意义上说,这不属于输入输出,称为读写比较合适。 因为输入输出一般指的是在计算机内存与计算机外的文件(外部设备也视为文件)之间 的数据传送。但由于C++的字符串流采用了 C++的流输入输出机制,因此往往也用输入和输出来表述读写操作。
字符串流对象关联的不是文件,而是内存中的一个字符数组,因此不需要打开和关闭文件。
每个文件的最后都有一个文件结束符,表示文件的结束。而字符串流所关联的字符数组中没有相应的结束标志,用户要指定一个特殊字符作为结束符,在向字符数组写入全部数据后要写入此字符。

字符串流类没有open成员函数,因此要在建立字符串流对象时通过给定参数来确立字符串流与字符数组的关联。即通过调用构造函数来解决此问题。建立字符串流对象的方法与含义如下。
建立输出字符串流对象

ostrstream类提供的构造函数的原型为:

ostrstream::ostrstream(char *buffer,int n,int mode=ios::out);

buffer是指向字符数组首元素的指针,n为指定的流缓冲区的大小(一般选与字符数组的大小相同,也可以不同),第3个参数是可选的,默认为ios::out方式。可以用以下语句建立输出字符串流对象并与字符数组建立关联:

  ostrstream strout(ch1,20);

作用是建立输出字符串流对象strout,并使strout与字符数组ch1关联(通过字符串流将数据输出到字符数组ch1),流缓冲区大小为20。
建立输入字符串流对象

istrstream类提供了两个带参的构造函数,原型为:

  istrstream::istrstream(char *buffer);
  istrstream::istrstream(char *buffer,int n);

buffer是指向字符数组首元素的指针,用它来初始化流对象(使流对象与字符数组建立关联)。可以用以下语句建立输入字符串流对象:

  istrstream strin(ch2);

作用是建立输入字符串流对象strin,将字符数组ch2中的全部数据作为输入字符串流的内容。

  istrstream strin(ch2,20);

流缓冲区大小为20,因此只将字符数组ch2中的,20个字符作为输入字符串流的内容。
建立输入输出字符串流对象

strstream类提供的构造函数的原型为:

  strstream::strstream(char *buffer,int n,int mode);

可以用以下语句建立输入输出字符串流对象:

  strstream strio(ch3,sizeof(ch3),ios::in|ios::out);

作用是建立输入输出字符串流对象,以字符数组ch3为输入输出对象,流缓冲区大小与数组ch3相同。

以上个字符串流类是在头文件strstream中定义的,因此程序中在用到istrstream、ostrstream和strstream类时应包含头文件strstream(在GCC中,用头文件strstream)。

[例] 将一组数据保存在字符数组中。

#include <strstream>
using namespace std;
struct student
{
  int num;
  char name[20];
  float score;
};
int main( )
{
  student stud[3]={1001,"Li",78,1002,"Wang",89.5,1004,"Fun",90};
  char c[50]; //用户定义的字符数组
  ostrstream strout(c,30); //建立输出字符串流,与数组c建立关联,缓冲区长
  for(int i=0;i<3;i++) //向字符数组c写个学生的数据
   strout<<stud[i].num<<stud[i].name<<stud[i].score;
  strout<<ends; //ends是C++的I/O操作符,插入一个'\\0'
  cout<<"array c:"<<c<<endl; //显示字符数组c中的字符
}

运行时在显示器上的输出如下:

array c:
1001Li781002Wang89.51004Fun90

以上就是字符数组c中的字符。可以看到:
1) 字符数组c中的数据全部是以ASCII代码形式存放的字符,而不是以二进制形式表示的数据。

2) 在建立字符串流strout时指定流缓冲区大小为30字节,与字符数组c的大小不同,这是允许的,这时字符串流最多可以传送30个字符给字符数组c。请思考:如果将流 缓冲区大小改为10字节,即:

  ostrstream.strout( c ,10);

运行情况会怎样?流缓冲区只能存放10个字符,将这10个字符写到字符数组c中。运行时显示的结果是:

  1001Li7810

字符数组c中只有10个有效字符。一般都把流缓冲区的大小指定与字符数组的大小 相同。

3) 字符数组c中的数据之间没有空格,连成一片,这是由输出的方式决定的。如果以后想将这些数据读回赋给程序中相应的变量,就会出现问题,因为无法分隔两个相邻的数据。为解决此问题,可在输出时人为地加入空格。如

  for(int i=0;i<3;i++)
    strout<<" "<<stud[i].num<<" "<<stud[i].name<<" "<<stud[i].score;

同时应修改流缓冲区的大小,以便能容纳全部内容,今改为字节。这样,运行时将输出:

  1001 Li 78 1002 Wang 89.5 1004 Fun 90

再读入时就能清楚地将数据分隔开。

[例] 在一个字符数组c中存放了个整数,以空格相间隔,要求将它们放到整型数组中,再按大小排序,然后再存放回字符数组c中。

#include <strstream>
using namespace std;
int main( )
{
  char c[50]="12 34 65 -23 -32 33 61 99 321 32";
  int a[10],i,j,t;
  cout<<"array c:"<<c<<endl; //显示字符数组中的字符串
  istrstream strin(c,sizeof(c)); //建立输入串流对象strin并与字符数组c关联
  for(i=0;i<10;i++)
   strin>>a[i]; //从字符数组c读入个整数赋给整型数组a
  cout<<"array a:";
  for(i=0;i<10;i++)
   cout<<a[i]<<" "; //显示整型数组a各元素
  cout<<endl;
  for(i=0;i<9;i++) //用起泡法对数组a排序
   for(j=0;j<9-i;j++)
     if(a[j]>a[j+1])
     {t=a[j];a[j]=a[j+1];a[j+1]=t;}
  ostrstream strout(c,sizeof(c)); //建立输出串流对象strout并与字符数组c关联
   for(i=0;i<10;i++)
     strout<<a[i]<<" "; //将个整数存放在字符数组c
  strout<<ends; //加入'\\0'
  cout<<"array c:"<<c<<endl; //显示字符数组c
  return 0;
}

运行结果如下:

array c: 12 34 65 -23 -32 33 61 99 321 32(字符数组c原来的内容)
array a: 12 34 65 -23 -32 33 61 99 321 32  (整型数组a的内容)
array c: -32 –12 32 33 34 61 65 99 321  (字符数组c最后的内容)

对字符串流的几点说明:
1) 用字符串流时不需要打开和关闭文件。

2) 通过字符串流从字符数组读数据就如同从键盘读数据一样,可以从字符数组读入字符数据,也可以读入整数、浮点数或其他类型数据。如果不用字符串流,只能从字符数组逐个访问字符,而不能按其他类型的数据形式读取数据。这是用字符串流访问字符数组的优点,使用方便灵活。

3) 程序中先后建立了两个字符串流strin和strout,与字符数组c关联。strin从字符数组c中获取数据,strout将数据传送给字符数组。分别对同一字符数组进行操作。甚至可以对字符数组交叉进行读写,输入字符串流和输出字符串流分别有流指针指示当前位 置,互不干扰。

4) 用输出字符串流向字符数组c写数据时,是从数组的首地址开始的,因此更新了 数组的内容。

5) 字符串流关联的字符数组并不一定是专为字符串流而定义的数组,它与一般的字符数组无异,可以对该数组进行其他各种操作。

通过以上对字符串流的介绍,大家可以看到:与字符串流关联的字符数组相当于内存中的临时仓库,可以用来存放各种类型的数据(以ASCII形式存放),在需要时再从中读回来。它的用法相当于标准设备(显示器与键盘),但标准设备不能保存数据,而字符数组中的内容可以随时用ASCII字符输出。它比外存文件使用方便,不必建立文件(不 需打开与关闭),存取速度快。但它的生命周期与其所在的模块(如主函数)相同,该模块的生命周期结束后,字符数组也不存在了。因此只能作为临时的存储空间。

(0)

相关推荐

  • 深入解析C++和JAVA的字符串

    所有的字符串类都起源于C语言的字符串,而C语言字符串则是字符的数组.C语言中是没有字符串的,只有字符数组. 谈一下C++的字符串:C++提供两种字符串的表示:C风格的字符串和标准C++引入的string类型.一般建议用string类型,但是实际情况中还是要使用老式C风格的字符串. 1.C风格的字符串:C风格字符串起源于C,并在C++中得到扩展.字符串存储在一个字符数组中,例如:        const char *str = "zhangdan";(不要忘掉最后的\0)       

  • C++ 将数据转为字符串的几种方法

    收集一下: 1\将int 转为 LPCTSTR 其实LPCTSTR可以直接使用CString直接代替,无需类型强制转换 CString str; int number=15; //str="15" str.Format(_T("%d"),number); //str=" 15"(前面有两个空格:4表示将占用4位,如果数字超过4位将输出所有数字,不会截断) str.Format(_T("%4d"),number); //str=

  • C++不使用变量求字符串长度strlen函数的实现方法

    本文实例讲述了C++不使用变量求字符串长度strlen函数的实现方法.分享给大家供大家参考.具体实现方法如下: 1.strlen的源码实现: size_t strlen(const char *str) //strlen不做内存非法判断,如果是NULL,会core. { const char *eos=str; while(*eos++); return (eos-str-1); } 2.常见面试题会要求不使用额外变量,实现strlen函数: 实现一: int strlen(const char

  • 深入解析C++中的字符数组和处理字符串的方法

    C++字符数组 用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符.字符数组具有数组的共同属性.由于字符串应用广泛,C和C++专门为它提供了许多方便的用法和函数. 字符数组的定义和初始化 定义字符数组的方法与前面介绍的类似.例如: char c[10]; c[0]=′I′;c[1]=′ ′;c[2]=′a′;c[3]=′m′;c[4]=′ ′;c[5]=′h′;c[6]=′a′;c[7]=′p′;c[8]=′p′;c[9]=′y′; 上面定义了c为字符数组,包含10个元素.在赋值

  • C++字符数组的输入输出和字符串结束标志使用讲解

    C++字符数组的输入输出 字符数组的输入输出可以有两种方法: 1) 逐个字符输入输出. 2) 将整个字符串一次输入或输出.例如有以下程序段: char str[20]; cin>>str; //用字符数组名输入字符串 cout<<str; //用字符数组名输出字符串 在运行时输入一个字符串,如: China 在内存中,数组str的状态如图5.9所示,在5个字符的后面自动加了一个结束符′\0′. 输出时,逐个输出字符直到遇结束符′\0′,就停止输出.输出结果为: China 如前所述

  • C++中字符串以及数组和指针的互相使用讲解

    C++字符串与指针 在C++中可以用3种方法访问一个字符串(在第5章介绍了前两种方法). 用字符数组存放一个字符串 [例]定义一个字符数组并初始化,然后输出其中的字符串. #include <iostream> using namespace std; int main( ) { char str[]="I love CHINA!"; cout<<str<<endl; return 0; } 运行时输出: I love CHINA! 用字符串变量存放

  • C++实现十六进制字符串转换为十进制整数的方法

    本文实例讲述了C++实现十六进制字符串转换为十进制整数的方法.分享给大家供大家参考.具体实现方法如下: /* * 将十六进制数字组成的字符串(包含可选的前缀0x或0X)转换为与之等价的整型值 */ #include <stdio.h> #include <math.h> /* 将十六进制中的字符装换为对应的整数 */ int hexchtoi(char hexch ) { char phexch[] = "ABCDEF"; char qhexch[] = &qu

  • C++实现数字转换为十六进制字符串的方法

    本文实例讲述了C++实现数字转换为十六进制字符串的方法.分享给大家供大家参考.具体如下: function toHex(number, min) { var hexes = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; var hex = ''; var min = min || 2; var nibble; do { nibble = number & 0x0f; number

  • C++中字符串查找操作的两则实例分享

    在一个字符串中找到第一个只出现一次的字符 题目: 在一个字符串中找到第一个只出现一次的字符.如输入 abaccdeff,则输出 b. 分析: 一个字符串存储的都是ASCII字符,其ASCII范围不超过255. 因此可以再创建一个255个元素的数组存储字符串中字符出现的个数. 通过两次遍历即可求得. 代码实现(GCC编译通过): #include "stdio.h" #include "stdlib.h" //查找字符串中第一个只出现一次的字符 char firstS

  • 解析C++中的字符串处理函数和指针

    C++字符串处理函数 字符串连接函数 strcat 其函数原型为 strcat(char[],const char[]); strcat是string catenate(字符串连接)的缩写.该函数有两个字符数组的参数,函数的作用是:将第二个字符数组中的字符串连接到前面字符数组的字符串的后面.第二个字符数组被指定为const,以保证该数组中的内容不会在函数调用期间修改.连接后的字符串放在第一个字符数组中,函数调用后得到的函数值,就是第一个字符数组的地址.例如: char str1[30]=″Peo

随机推荐