当前位置:首页技术教程第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人
第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人
°
  • 素材类型: 原创-素材
  • 上传时间:

IO库(Stream)是一个用于处理输入/输出(I/O)操作的库。它提供了一组类和函数,用于读取和写入数据,包括文件、设备和其他数据源。

IO库中的Stream类是一个基础类,用于各种I/O操作。它提供了一些基本的方法和操作符,如打开和关闭流、读取和写入数据、定位读写指针等。通过继承和重载,Stream类可以用于不同的I/O场景,如文件读写、网络通信等。
除了Stream类本身,IO库还提供了许多其他的类和组件,以支持不同类型的I/O操作。例如,FileStream类用于读写文件,NetworkStream类用于读写网络连接,MemoryStream类用于读写内存中的数据。这些类通常与Stream类一起使用,以实现更复杂的I/O操作。
此外,IO库还提供了一些其他的工具和功能,如文件操作、字符串处理、缓冲区管理等等。这些工具和功能可以与Stream类一起使用,以简化I/O操作的开发。
总体来说,IO库(Stream)是一个强大的工具,用于处理各种I/O操作。通过使用该库,开发人员可以方便地读取和写入数据,而无需关心底层细节。这有助于提高开发效率,减少错误并简化代码。
第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

10. The IO library(Stream)

10.1.C IO

10.1.1.

数据流:

指程序与数据的交互是以流的形式进行的.进行 C 语言文件的存取时,都会先进行“打开

文件”操作,这个操作就是在打开数据流,而“关闭文件”操作就是关闭数据流。

10.1.2.

缓冲区(Buffer)

指在程序执行时,所提供的额外内存,可用来暂时存放做准备执行的数据.它的设置是为

了提高存取效率,因为内存的存取速度比磁盘驱动器快得多.

C++ 语言中带缓冲区的文件处理:

C++ 语言的文件处理功能依据系统是否设置“缓冲区”分为两种:

 一种是设置缓冲区

 另一种是不设置缓冲区

当使用标准 I/O 函数(包含在头文件 cstdio 中)时,系统会自动设置缓冲区,并通过数据

流来读写文件.

当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息

拷贝到缓冲区内,然后程序再从缓冲区中读取所需数据,如下图所示:

文件读:

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

文件写:

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

10.1.3. 文件类型

分为文本文件和二进制文件两种.

 文本文件:

是以字符编码的方式进行保存的,只是计算机以二进制表示数据在外部存储介质上的另一种存放形式.它所存放的每一个字节都可以转换为一个可读字符当向文件中写入数据时,windows 中一旦遇到”换行”字符(ASCII 码为 10)则会转换成”回车-换行”(ASCII 值为 13,10).在读取数据的时候,一遇到”回车-换行”的组合 ASCII 值为 13,10),则会转换成为”换行”字符(ASCII 码为 10)

 二进制文件:

将内存中数据原封不动的读取和写入文件中。二进制文件适用于非字符为主的数据.如果以记事本打开,只会看到一堆乱码.当按照文本方式其实,除了文本文件外,所有的数据都可以算是二进制文件.二进制文件的优点在于存取速度快,占用空间小,以及可随机存取数据.在文件操作中因为文本打开方式和二进制文件打开方式会导致数据读取和写入换行时候的不同所以在进行文件操作时候要注意写入和读取的方式要保持一致,如果采用文本方式写入,应该采用文本方式读取,如果采用二进制方式写入,就应该用二进制方式读取,但是不管是文本文件还是二进制文件,如果采用统一的二进制方式写入和读取数据都是不会出错的,不管是文本文件还是二进制文件,都可以采用二进制方式或者文本方式打开,然后进行写入或读取.但是对于二进制文件来说,如果以文本凡是读取数据时候可能会出现一些问题。

10.1.4. 文件存取方式

包括顺序存取方式和随机存取方式两种.

 顺序读取:

也就是从上往下,一笔一笔读取文件的内容.保存数据时,将数据附加在文件的末尾.这种存取方式常用于文本文件,而被存取的文件则称为顺序文件.

 随机存取:

多半以二进制文件为主.它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位.

10.1.5. 借助文件指针读写文件

我们如果要访问文件,要借助于文本变量,即文件指针 FILE *才可以完成。文件在进行读写操作之前要先打开,使用完毕要关闭.所谓打开文件,实际上是建立文件的各种有关信息,并使文件指针指向该文件,以便进行其它操作.关闭文件则断开指针与文件之间的联系,也就禁止再对该文件进行操作。

10.1.6. 操作流图

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

10.2.C++ 输入输出 IO

10.2.1. 引例

C++用类包装了,FILE*.

10.2.2. cincout说起

cin 和 cout 充当了 scanf 和 printf 的功能。但他们并不是函数。而是类对象,那么我们有必要了解一下,他们是哪些类的对像。

10.2.3. io类图关系

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

简化图和要掌握的流类。

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人
第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

10.2.4. 流类综述

10.2.4.1. IO 对象不可复制或赋值

#include <iostream>
#include <fstream>
fstream printf(fstream fs)
{
}
using namespace std;
int main()
{
    fstream fs1,fs2;
//    fs1 = fs2;
//    fstream fs3(fs2);
    return 0;
}

10.2.4.2. IO 对象是缓冲的

int main()
{
    cout<<"aldksfj;lasdkfj;alsd";
    while(1);
    return 0;
}

下面几种情况会导致刷缓冲

1,程序正常结束,作为 main 函数结束的一部分,将清空所有缓冲区。

2,缓冲区满,则会刷缓冲。

3,endl, flush 也会刷缓冲。

4,在每次输出操作执行完后,用 unitbuf 操作符设置流的内部状态,从而清空缓冲区。

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    cout<<"hi"<<endl;
    cout<<"hi"<<flush;
    cout<<unitbuf<<"hi";
    while(1);
    return 0;
}

10.2.4.3. 重载了<< 和 >>运算符

    __ostream_type&
    operator<<(long __n)
    { return _M_insert(__n); }
    __ostream_type&
    operator<<(unsigned long __n)
    { return _M_insert(__n); }
    __ostream_type&
    operator<<(bool __n)
    { return _M_insert(__n); }

10.2.5. 标准输出

C++提供的输出流对象有:

cout输出基本类型数据时,不必考虑数据是什么类型,系统会自动判断,选择相应的

重载函数;输出用户自己定义的类型数据时,要重载<<运算符。

cerr是在屏幕上显示出错信息,与 cout 用法类似,不同的是只能在屏幕上,而不能在

磁盘文件上输出错误信息;

clog用法与 cerr 类似,不同点是它带有缓冲区。

I/O 流的常用控制符

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

10.2.5.1. iomanip

引用流算子的原因是,系统函数格式化并不好用。

int main()
{
    cout.unsetf(ios::dec);
    cout.setf(ios::hex);
    cout<<1234<<endl;
    cout.unsetf(ios::hex);
    cout<<1234<<endl;
    return 0;
}

输出就涉及到格式化,系统提供的方案特别的复杂。我们采用 iomanip 中的方案,分

别示例:

1)用格式控制符控制输出

输出不同进制的数:dec(十进制)、hex(十六进制)、oct(八进制)

    int n=20;
    cout<<"设置进制:"<<endl;
    cout<<"十进制 :"<<n<<endl;
    cout<<"十六进制:"<<hex<<n<<endl;
    cout<<"八进制 :"<<oct<<n<<endl;
    cout<<"十进制 :"<<dec<<n<<endl;

2)设置域宽

setw(n), n 小于实际宽度时,按实际宽度输出,它一次只控制一个数值输出。

    int m=1234;
    cout<<"设置域宽: "<<endl;
    cout<<setw(3)<<m<<endl;
    cout<<setw(5)<<m<<endl;
    cout<<setw(10)<<m<<endl;

3)设置填充字符

setfill(c),需要与 setw(n)合用。

    int x=1234;
    cout<<"设置填充字符: "<<endl;
    cout<<setfill('*')<<setw(5)<<x<<endl;
    cout<<setw(10)<<x<<endl;

4)设置对齐方式:

setiosflags(ios::left)(左对齐)、setiosflags(ios::right)(右对齐)

    int y=1234;
    cout<<"设置对齐方式"<<endl;
    cout<<setfill(' ');
    cout<<setiosflags(ios::left)<<setw(10)<<y<<endl;
    cout<<setiosflags(ios::right)<<setw(10)<<y<<endl;

5) 强制显示

强制显示小数点和尾 0:setiosflags(ios::showpoint)

强制显示符号:setiosflags(ios::showpos)

    double d1=10/5,d2=22.0/7;
    cout<<"显示小数点、尾和数符: "<<endl;
    cout<<d1<<endl;
    cout<<setiosflags(ios::showpoint)<<d1<<endl;
    cout<<setiosflags(ios::showpos)<<d2<<endl;
    cout<<resetiosflags(ios::showpos);

6)设置浮点数的输出是以科学记数法还是定点数

setiosflags(ios::scientific)(科学记数法)

setiosflags(ios::fixed)(定点数)

double dd=123.4567;
cout<<setiosflags(ios::scientific)<<dd<<endl;
cout<<setiosflags(ios::fixed)<<dd<<endl;

7)设置精度(有效数字个数)

setpreciion(n)自动四舍五入

    double ddd=123.4567;
    cout<<setprecision(2)<<dd<<endl;
    cout<<setprecision(3)<<dd<<endl;
    cout<<setprecision(4)<<dd<<endl;
    cout<<setprecision(5)<<dd<<endl;

8)输出十六进制数时控制英文字母的大小写

setiosflags(ios::uppercase)

resetiosflags(ios::uppercase)

    int num=510;
    cout<<"以大小写方式输出进制数: "<<endl;
    cout<<"16 进制数(默认:小写方式):"<<hex<<num<<endl;
    cout<<"以大写方式输出进制数: "<<setiosflags(ios::uppercase)<<hex<<num<<endl;
    cout<<"恢复小写方式输出进制数: "<<resetiosflags(ios::uppercase)<<hex<<num<<endl;

10.2.5.2. 成员函数

格式:ostream put( char )

功能:输了一个字符。

#include <iostream>
using namespace std;
int main()
{
    char str[]="Programming with C++";
    for( int i=sizeof(str)/sizeof(str[0])-2 ; i>=0; i--)
        cout.put(*(str+i));
    cout.put('\n');
    return 0;
}

10.2.6. 标准输入cin

在 C++中,默认的标准输入设备是键盘,在 iostream 文件中定义了 cin 输入流对象。

cin 对象与提取运算符>>、变量名或数组名一起构成输入语句,形式为 C++的格式化输入。

cin>>…>>…>>…;,能够连续输入多项内容。只要是基本数据类型,不管是 int、double、float,还是 char、char *等,都可以写成这种形式,这给用户提供了很大的方便。如果要输入用户自己定义的类型数据,就要用友元方式重载>>运算符;

#include <iostream>
using namespace std;
int main()
{
    int a;
    double b;
    char buf[1024]; //string buf;
    cin>>a>>b>>buf; //读入字符串时遇到空格则止 12 23.5 aa bb cc dd
    cout<<a<<endl;
    cout<<b<<endl;
    cout<<buf<<endl;
    return 0;
}

10.2.6.1. 成员函数

a)

格式:char cin.get()

功能:读入一个字符并返回(包括回车、tab、空格等空白字符)

#include <iostream>
using namespace std;
int main()
{
    char ch;
    while( (ch=cin.get()) !=EOF) //EOF 为文件结束符,按 ctrl+d 输入
      cout.put(ch);
    return 0;
}

b)

格式:istream cin.get(ch)

功能:读入一个字符,如果读取成功则返回非 0 值(真),如失败(遇到文件结束符)

则函数返回 0 值(假)。

#include <iostream>
using namespace std;
int main()
{
    char ch;
    while(cin.get(ch)) //get 函数返回的是,istream & 可实现链实编程。
    {
        cout.put(ch);
    }
    return 0;
}

c)

格式:istream cin.get(字符数组,字符个数 n,终止字符)

或 istream cin.get(字符指针,字符个数 n,终止字符)

功能:从输入流中读取 n-1 字符,赋给字符数组或字符指针所指向的数组。如果在读取 n-1 个字符之前遇到终止字符,则提前结束。如果成功则返回非 0,失败则返回 0。

#include <iostream>
using namespace std;
int main()
{
    char str[80];
    cout<<"请输入一个字符串:"; //cin>>buf; aa bb cc dd
    cin.get(str,80,'a');
    cout<<str<<endl;
    return 0;
}

d)

格式:cin.getline(字符数组或字符指针,字符个数 n[,终止字符])

功能:与带三个参数的 get()功能类似,从输入流中读取 n-1 字符,赋给字符数组 或

字符指针所指向的空间。如果在读取 n-1 个字符之前遇到终止字符(如果不写, 默

认为’\n’),则提前结束。

e)

其它:

cin.ignore(n,终止字符) 跳过流中的 n 个字符,或遇到终止字符为止(包含)

,默认参

数忽略一个字符。

cin.peek(); //窥视 当前指针未发生移动

cin.putback()//回推 插入当前指针位置

#include <iostream>
using namespace std;
int main()
{
    char ch[20];
    cin.get(ch,20,'/'); // i like c/ i like c++ also/
    cout<<"the first part is :"<<ch<<endl;
    cin.ignore(10, 'i');
    cin.putback('i');
    char peek = cin.peek();
    cout<<"peek is :"<<peek<<endl;
    cin.get(ch,20,'/');
    cout<<"this second part is:"<<ch<<endl;
    return 0;
}

10.2.7. 其它

eof()判断文件的结束标志,未到文件尾返回 false,到文件尾返回 true。

10.3.C++ 文件 IO

10.3.1. 文件的概念

一切设备皆文件。Everything is a file.

10.3.2. 文件流类与文件流对象

对文件的操作是由文件流类完成的。文件流类在流与文件间建立连接。由于文件流分

为三种:文件输入流、文件输出流、文件输入/输出流,所以相应的必须将文件流说明为

ifstream、ofstream 和 fstream 类的对象,然后利用文件流的对象对文件进行操作。

对文件的操作过程可按照一下四步进行:即定义文件流类的对象、打开文件、对文件

进行读写操作、关闭文件,下面分别进行介绍。

10.3.3. 文件的打开和关闭

10.3.3.1. 定义流对象

//流类 流对象;
ifstream ifile; //定义一个文件输入流对象
ofstream ofile; //定义一个文件输出流对象
fstream iofile; //定义一个文件输出/输入流对象

10.3.3.2. 打开文件

定义了文件流对象后,就可以利用其成员函数 open()打开需要操作的文件,该成员函数的函数原型为:

void open(const unsigned char *filename,int mode,int access=filebuf:openprot);

其中:filename 是一个字符型指针,指定了要打开的文件名;mode 指定了文件的打开方式,其值如下表所示;access 指定了文件的系统属性,取默认即可:

mode :在 ios 类中定义的文件打开方式

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

说明:

1)在实际使用过程中,可以根据需要将以上打开文件的方式用“|”组合起来。如:

ios::in|ios::out 表示以读/写方式打开文件
ios::in|ios:: binary 表示以二进制读方式打开文件
ios::out|ios:: binary 表示以二进制写方式打开文件
ios::in|ios::out|ios::binary 表示以二进制读/写方式打开文件

2)如果未指明以二进制方式打开文件,则默认是以文本方式打开文件。

3)对于 ifstream 流,mode 参数的默认值为 ios::in,对于 ofstream 流,mode 的默认值为 ios::out|ios::trunc, fstream 流,mode 的默认值为 ios::int|ios::out

4) 也可以通过,构造函数打开文件。

5) 出错处理是通过,对类对象进行判断的。若文件打开成功,返回 1,否则返回 0

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    ifstream ifs("xxx");
    if(!ifs)
        cout<<"open error"<<endl;
    ofstream ofs("yyy");
    if(!ofs)
        cout<<"open error"<<endl;
    fstream fs;
    fs.open("zzz",ios::in|ios::out|ios::trunc);
    if(!fs)
        cout<<"open error"<<endl;
    return 0;
}

10.3.3.3. 文件的关闭

在文件操作结束(即读、写完毕)时应及时调用成员函数 close()来关闭文件。该函

数比较简单,没有参数和返回值。

10.3.4. (cin)和(!cin)的原理分析

在判断文件打开成功与否或是连续从流中读取数据时,就要用到对流对像的操作,比如 if(!cin) 或是 whie(cin) 等等。

代码 while(cin>>val),我们都知道 cin 是一个流对象,而>>运算符返回左边的流对象,也就是说 cin>>val 返回 cin,于是 while(cin>>val)就变成了 while(cin),问题就变成了一个流对象在判断语句中的合法性。

不管是 while(cin)还是 if(cin),都是合法的,为什么呢?我们自己定义一个类,然后定义该类的对象,然后使用 if 语句来判断它是不合法的。这说明,流对象具有某种转换函数,可以将一个流对象转换成判断语句可以识别的类型。

打开 iostream.h 文件,找到 cin 的定义,发现是来自于 istream.h,其中的模板类basic_istream 继承自 basic_ios,打开 basic_ios 的定义,发现它有两个重载函数。operator void*() const bool operator!() const。这两个函数使得流对象可作为判断语句的内容。

/**
* @brief The quick-and-easy status check.
*
* This allows you to write constructs such as
* <code>if (!a_stream) ...</code> and <code>while(a_stream) ...</cod
e>
*/
operator void*() const
{
    return this->fail() ? 0 : const_cast<basic_ios*>(this);
}
bool operator!() const
{
    return this->fail();
}

需要指出的是,上述两个类型转换都是隐式的。

因此,可以简单的理解调用过程为:

    while(cin) =====> while(!cin.fail()) //while the stream is OK
    while(!cin) =====> while(cin.fail()) //while the stream is NOT OK

简单测试:

#include<iostream>
using namespace std;
class A
{
public:
    A(){}
    ~A(){}
    operator void *()const
    {
        cout<<"cast to void*; ";
        return (void *)this;
    }
    bool operator!() const
    {
        cout<<"cast to bool; ";
        return true;
    }
};
int main()
{
    A a;
    if(a) cout<<"first"<<endl;
    if(!a) cout<<"second"<<endl;
    return 0;
}

10.3.5. 流文件状态与判断

 eof()

如果读文件到达文件末尾,返回 true。

 fail()

除了与 bad() 同样的情况下会返回 true 以外,加上格式错误时也返回 true ,例如当想要读入一个整数,而获得了一个字母的时候。

 bad()

如果在读写过程中出错,返回 true 。例如:当我们要对一个不是打开为写状态的文件进行写入时,或者我们要写入的设备没有剩余空间的时候。

 good()

这是最通用的:如果调用以上任何一个函数返回 true 的话,此函数返回 false 。

 clear()

要想重置以上成员函数所检查的状态标志,你可以使用成员函数 clear(),没有参数。

10.3.6. 文件的读写操作

在打开文件后就可以对文件进行读写操作了。

从一个文件中读出数据,可以使用文件流类的 get、getline、read 成员函数以及运算符“>>”;

而向一个文件写入数据,可以使用其 put、write 函数以及插入符“<<”,如下表所示:

10.3.6.1. 流状态的查询和控制

We might manage an input operation as follows:

可以如下管理输入操作

int ival;
// read cin and test only for EOF;
//loop is executed even if there are other IO failures
while (cin >> ival, !cin.eof()) {
    if (cin.bad())                    // input stream is corrupted; bail out
        throw runtime_error("IO stream corrupted");
    if (cin.fail()) {                 // bad input
        cerr<< "bad data, try again";     // warn the user
        cin.clear(istream::failbit);     // reset the stream
        continue; // get next input
}
    // ok to process ival
}

This loop reads cin until end-of-file or an unrecoverable read error occurs. The condition uses a comma operator . Recall that the comma operator executes by evaluating each operand and returns its rightmost operand as its result. The condition, therefore, reads cin and ignores its result. The result of the condition is the result of !cin.eof(). If cin hit end-of-file, the condition is false and we fall out of the loop. If cin did not hit end-of-file, weenter the loop, regardless of any other error the read might have encountered.

这个循环不断读入 cin,直到到达文件结束符或者发生不可恢复的读取错误为止。循环条件使用了逗号操作符。回顾逗号操作符的求解过程:首先计算它的每一个操作数,然后返回最右边操作数作为整个操作的结果。因此,循环条件只读入 cin 而忽略了其结果。该条件的结果是 !cin.eof() 的值。如果 cin 到达文件结束符,条件则为假,退出循环。如果 cin 没有到达文件结束符,则不管在读取时是否发生了其他可能遇到的错误,都进入循环。

Inside the loop, we first check whether the stream is corrupted. If so, we exit by throwing an exception . If the input was invalid, we print a warning,and clear the failbit state. In this case, we execute a continue to return to the start of the while to read another value into ival. If there were no errors, the rest of the loop can safely use ival.

在循环中,首先检查流是否已破坏。如果是的放,抛出异常并退出循环。如果输入无效,则输出警告并清除 failbit 状态。在本例中,执行 continue 语句,回到 while 的开头,读入另一个值 ival。如果没有出现任何错误,那么循环体中余下的部分则可以很安全地使用 ival。

10.3.6.2. 读写文件本文件

读出:

 重载运算符>>

 int get();

 istream get(int);

 istream get(char*,int n, char deli )

 istream getline(char * ,int n);

写入:

 重载运算符 <<

 osream put(int)

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    fstream ifs("src.txt",ios::in);
    if(!ifs)
    {
        cout<<"open error"<<endl;
    return -1;
    }
    fstream ofs("dest.txt",ios::out|ios::trunc);
    if(!ofs)
    {
        cout<<"open error"<<endl;
        return -1;
    }
//     int data;
//     while(ifs>>data,!ifs.eof()) // 只能以 空格 table 回车 作为标志
//     {
//         cout<<"x"<<endl;
//        ofs<<data<<" ";
//     }
//    char ch;
//     while(ifs.get(ch),!ifs.eof())
//     {
//     ofs.put(ch);
//     }
//     ifs.close();
//     ofs.close();
    char buf[1024];
    while(ifs.get(buf,1024,'\n'))
{
    while(ifs.peek() == '\n')
        ifs.ignore();
    ofs<<buf<<endl;
    }
    ifs.close();
    ofs.close();
    return 0;
}

10.3.6.3. 读写二进制文件

ostream & write(const char * buffer,int len);
istream & read(char * buff, int len);
#include <iostream>
#include <fstream>
using namespace std;
struct Student
{
    char name[100];
    int num;
    int age;
    char sex;
};
int main()
{
//     Student s[3] = {
//         {"li",1001,18,'f'},
//         {"Fun",1002,19,'m'},
//         {"Wang",1004,17,'f'}
//     };
//     ofstream ofs("student.data",ios::out|ios::trunc|ios::binary);
//     if(!ofs){
//         cout<<"open error"<<endl;
//     }
// for(int i=0; i<3; i++)
//     {
// ofs.write((char*)&s[i],sizeof(s[i]));
//     }
//     ofs.close();
    Student s;
ifstream ifs("student.data",ios::int|ios::binary);
    if(!ifs)
        cout<<"open error"<<endl;
    ifs.seekg(sizeof(stu),ios::beg);
    while(ifs.read((char*)&s,sizeof(Student)),!ifs.eof())
    {
        cout<<"Name "<<s.name<<endl;
        cout<<"Num "<<s.num<<endl;
        cout<<"Age "<<s.age<<endl;
        cout<<"Sex "<<s.sex<<endl;
        cout<<"---------------"<<endl;
    }
    ifs.close();
    return 0;
}

10.3.7. 随机读写函数

与文件指针相关的函数如下:

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

用于输入的函数。p 代表 put 的意思,用于输出函数。如果是既可输入又可输出的文件,则任意使用。

参照位置

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

代码示例:

infile.seekg(100); //输入文件中的指针向前移到 100 个字节的位置
infile.seekg(-50,ios::cur); //输入文件中的指针从当前位置后移 50 个字节
outfile.seekp(-75,iso::end); //输出文件中指针从文件尾后移 50 个字节

10.3.8. 综合练习:

有 5 个学生的数据,要求

1,把它们存到磁盘文件中;

2,将磁盘文件中的第 1 3 5 个学生数据读入程序,并显示出来;

3,将第 3 个学生的数据修改后存回磁盘文件中的原有位置;

4,从磁盘文件读入修改后的 5 个学生数据并显示出来。

提示: 要实现以上要求,需要解决 3 个问题

1,由于同一磁盘文件在程序中需要频繁地进行输入和输出,因此可将文件的工

作方式指定为输入输出文件,ios::in|ios::out|ios::binary。

2,正确计算好每次访问时指针的定位,即正确使 seekg 或 seekp 函数。

3 正确进行文件中数据的重写 (更新)。

代码:

#include <fstream>
using namespace std;
struct student
{int num;
    char name[20];
    float score;
};
int main()
{
    int i;
    student stud[5]={1001,"Li",85,
                    1002,"Fun",97.5,
                    1004,"Wang",54,
                    1006,"Tan",76.5,
                    1010,"ling",96};
    fstream iofile("stud.dat",ios::in|ios::out|ios::binary);
    if(!iofile)
    {
cerr<<"open error!"<<endl;
abort();
}
    for(i=0;i<5;i++)
        iofile.write((char *)&stud[i],sizeof(stud[i]));
    student stud1[5];
    for(i=0;i<5;i=i+2)
    {
    iofile.seekg(i*sizeof(stud[i]),ios::beg);
    iofile.read((char *)&stud1[i/2],sizeof(stud1[i]));
    cout<<stud1[i/2].num<<" "<<stud1[i/2].name<<" "<<stud1[i/2].score<<endl;
}
    cout<<endl;
    stud[2].num=1012;
    strcpy(stud[2].name,"Wu");
    stud[2].score=60;
    iofile.seekp(2*sizeof(stud[0]),ios::beg);
    iofile.write((char *)&stud[2],sizeof(stud[2]));
    iofile.seekg(0,ios::beg);
    for(i=0;i<5;i++)
    {
        iofile.read((char *)&stud[i],sizeof(stud[i]));
        cout<<stud[i].num<<" "<<stud[i].name<<" "<<stud[i].score<<endl;
    }
    iofile.close();
    return 0;
}

本章完

温馨提示:

文章标题:第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

文章链接:https://www.xiciw.com/jsjc/1215.html

更新时间:2024年02月03日

本站大部分内容均收集于网络!若内容若侵犯到您的权益,请发送邮件至:xiciw#qq.com我们将第一时间处理!

资源所需价格并非资源售卖价格,是收集、整理、编辑详情以及本站运营的适当补贴,并且本站不提供任何免费技术支持。

                               

所有资源仅限于参考和学习,版权归原作者所有,更多请阅读菜鸟资源服务协议

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
技术教程

第十六章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-2-5 9:31:00

Macos教程Windows教程技术教程

在浏览器中“ERR_NAME_NOT_RESOLVED”错误如何修复此 DNS 错误

2024-2-7 4:48:19

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索