c++(7) IO

C++ IO详解

1.输入输出流概念

输入输出是数据的传递过程,数据如流水一般从一处流向另一处,C++形象的将此过程称为流。

输入操作:是控制序列中的字节内容从一个设备流入内存

输出操作:是控制序列中的字节内容从内存流向某个设备

2.IO概念

根据I/O操作对象的不同,将I/O操作分为三类:

(1)标准I/O——以标准输入、输出设备为操作对象

(2)文件I/O——以磁盘文件为操作对象

(3)字符串I/O——以内存中指定的空间(通常为字符数组)为操作对象

3.流类库

输入输出操作:数据流出 流入stream

C++中输入输出操作由I/O类库实现,该类库是一个庞大的继承机构,其根基类为 ios,直接派生出4个类:输入流类*istream*、输出流类*ostream*、文件流基类 *fstreambase*、字符串流基类*strstreambase*

4.缓冲区概念

在对数据进行输入输出时,为了减少输入输出的次数,节省计算机资源,常常需要使用到缓冲区,在C++中,系统提供了一个缓冲区流类库,它是以抽象类streambuf 为父类的类层次,主要完成信息通过缓冲区的交换。

所谓缓冲区,就是当数据传递时,在内存中为每一个数据流开辟的一个用来存放数据流中的数据的地方缓冲输入或输出的数据,又称为缓存。

(1)缓冲区满时

(2)执行flush()函数

(3)执行endl语句

(4)关闭文件

 

5.标准输入输出流

1.提取和插 入是通过在流类库中重载“>>” 输入 和“<<” 输出 运算符来实现的。

2.预定义流对象

261993836a1c437c9457208eba1f353e

6.标准输出流类常用成员函数

1.put()函数 输出单个字符

ostream& put(count char ch);
    char ch = 'abcd';

cout.put(ch) << endl;//从缓冲区读取 读取的是最后一个字符
//函数返回值 是ostream& 所以可以重复调用
cout.put('a').put('b').put('c');

2.write()函数:用于输出一个字符串的部分或全部字符

ostream& write(const char* str, int n);
    const char* str = "我是";
cout.write(str, strlen(str)).put('\n');
    //还是返回值调用
7.标准输入流类常用成员函数

istream流类还提供了get()getline()read()等成员函数用于完成多种形式的数据读入:

get()实现字符的输入;getline()实现字符串的输入;read()实现无格式输入等。

(1)get()函数

int get();

istream& get(char& ch);

istream& get(char* dst, streamsize size, char delimiter=’\0’);

第一种形式:表示从输入流中读取一个字符,返回该字符的int值,遇到文件 结束符时,返回EOF。

第二种形式:表示从输入流中读取一个字符,存储在ch中。

第三种形式:第三个参数是字符串的结束符。用于读取字符串,遇到指定的结 束字符或读满指定数量的字符时,函数返回。表示从输入流中连续读取最多 size-1个字符(因为最后一个字符要留给字符‘\0’),也可以设置结束符为别 的字符,遇到这个字符就结束读取,并且结束符不包含在所读取的字符串内。 如果一直读取到size-1个字符也没有遇到结束符,则在结束读取时会自动在末 尾加‘\0’。

    //1
   cout << "第一种" << cin.get() << endl;
   cin.get();
   //2
   char m;
   cin.get(m);
   cout << m << endl;
   cin.get();
   //3
   char zm[8] ;
   cin.get(zm, 5, 'f');

 

(2)getline()函数

getline()函数可以一次读取一 个字符串

第三个是结束符 我的理解是输入时碰到第三个参数对应的结束输入

istream& getline(char* dst, streamsize size, char delimiter=’\n’);
    char sp[10];
cin.getline(sp, 10, 'f');
cout << sp << endl;
//输入 abcdefg
//输出 abcde

(3)get()和getline()函数的比较

get()、getline()函数在碰到结束符后都停止读入,get()函数将结束符仍留在输入缓冲中,getline()函数会将结束符从输入缓冲中读走并丢弃。

 

(4)read()函数

从输入流中读取部分或全部数据到指定的内存空间。

istream& read(char* dst, streamsize size);

第一个参数是地址 后面是大小

    int arr[10];
cin.read((char*)arr, 10);
cout <<(char ) arr[1] << endl;
cout << (char)arr[0] << endl;
8.格式化控制

C++的输入输出比C语言的安全,因为C++的没有格式,而C语言的需要控制符来规定格式,比如整型要%d,字符要%c。但是C++不需要。因为C++里,在istream和ostream类(这两个类都是在iostream中声明的)中分别有一组成员函数对位移运算符“<<”和“>>”进行重载,以便能用它输入或输出各种标准数据类型的数据。对于不同的标准数据类型要分别进行重载

(1)格式化控制

QQ截图20230530152436

 

        double num = 3.1415926232323;
   cout << setprecision(1) << showpos<<oct<<num << endl;
9.文件IO
(1).基础了解

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

(2).简单的写入文件
打开:void open (const char* filename, ios_base::openmode mode = ios_base::out);
filename:文件的名称
mode :打开方式,默认是以输出方式打开文件,如果已有此名字的文件,则将其原有内容全部清除    
参数作用
ios::in 为输入(读)而打开文件
ios::out 为输出(写)而打开文件
ios::ate 初始位置:文件尾
ios::app 所有输出附加在文件末尾
ios::trunc 如果文件已存在则先删除该文件
ios::binary 二进制方式
关闭:void close();
void main() {
 
const char* url = "https://www.cnblogs.com/lzfyz/";
ofstream file;
file.open("I:\\doc.dat", ios::out);
file.write(url, 40);
file.close();

}

为什么要关闭文件 上面程序中不调用 close() 方法,也能成功向 url.txt 文件中写入 url 字符串。这是因为,当文件流对象的生命周期结束时,会自行调用其析构函数,该函数内部在销毁对象之前,会先调用 close() 方法切断它与任何文件的关联,最后才销毁它。

当文件流对象未关联任何文件时,调用 close() 方法会失败,其会为文件流设置 failbit 状态标志,该标志可以被 fail() 成员方法捕获。

(3).使用流类的构造函数打开文件
ifstream inFile("c:\\tmp\\test.txt", ios::in);
10.C++文本文件读写操作详解

C++ 标准库中,提供了 2 套读写文件的方法组合,分别是: 使用 >> 和 << 读写文件:适用于以文本形式读写文件; 使用 read() 和 write() 成员方法读写文件:适用于以二进制形式读写文件。

(1).左移 右移 读写文件
    #include <iostream>
   #include <fstream>
   using namespace std;
   int main()
  {
       int x,sum=0;
       ifstream srcFile("in.txt", ios::in); //以文本模式打开in.txt备读
       if (!srcFile) { //打开失败
           cout << "error opening source file." << endl;
           return 0;
      }
       ofstream destFile("out.txt", ios::out); //以文本模式打开out.txt备写
       if (!destFile) {
           srcFile.close(); //程序结束前不能忘记关闭以前打开过的文件
           cout << "error opening destination file." << endl;
           return 0;
      }
       //可以像用cin那样用ifstream对象
       while (srcFile >> x) {
           sum += x;
           //可以像 cout 那样使用 ofstream 对象
           destFile << x << " ";
      }
       cout << "sum:" << sum << endl;
       destFile.close();
       srcFile.close();
       return 0;
  }
(2).C++ read()和write()读写二进制文件

read() 方法用于以二进制形式从文件中读取数据;write() 方法用于以二进制形式将数据写入文件。

ostream & write(char* buffer, int count);
istream & read(char* buffer, int count);

write() read() 方法会从文件写指针指向的位置将二进制数据写入。所谓文件写指针,是是 ofstream 或 fstream 对象内部维护的一个变量,文件刚打开时,文件写指针指向的是文件的开头(如果以 ios::app 方式打开,则指向文件末尾),用 write() 方法写入 n 个字节,写指针指向的位置就向后移动 n 个字节。

cstu sz;
   ofstream outFilec
   while (cin >> sz.szname >> sz.age)
  {


       outFile.write((char*)&sz, sizeof(sz));
       // 获取大小 把成员变量的值写入进去
       outFile.close();
  }
   
   cstu s;
   ifstream ouy("I:\\doc.dat", ios::out | ios::binary);
   while (ouy.read((char*)&s, sizeof(s)))
  {
       cout << s.age << "\n" << s.szname << endl;

  }
(3).C++ get()和put()读写文件详解
ostream& put (char c);

向指定文件中写入单个字符。

int get();
istream& get (char& c);

第一种语法格式的返回值就是读取到的字符,只不过返回的是它的 ASCII 码,如果碰到输入的末尾,则返回值为 EOF。第二种语法格式需要传递一个字符变量,get() 方法会自行将读取到的字符赋值给这个变量。

    ///写
char cm='a';
   ofstream op("I:\\doc.dat", ios::out | ios::binary);


   while (cin>>cm)
  {
       op.put(cm);

  }
///读
   char qq = 'a';
   ifstream op("I:\\doc.dat", ios::out | ios::binary);


   while (op.get(qq))
  {
       cout << qq << endl;

  }
(4).C++ getline():从文件中读取一行字符串
istream & getline(char* buf, int bufSize);
istream & getline(char* buf, int bufSize, char delim);
   char qq [40];
   ifstream op("I:\\doc.dat", ios::out | ios::binary);
   op.getline(qq, 40);
   cout << qq << endl;

 

注意,由于文件存放在硬盘中,硬盘的访问速度远远低于内存。如果每次写一个字节都要访问硬盘,那么文件的读写速度就会慢得不可忍受。因此,操作系统在接收到 put() 方法写文件的请求时,会先将指定字符存储在一块指定的内存空间中(称为文件流输出缓冲区),等刷新该缓冲区(缓冲区满、关闭文件、手动调用 flush() 方法等,都会导致缓冲区刷新)时,才会将缓冲区中存储的所有字符“一股脑儿”全写入文件。

了解内容 : C++移动和获取文件读写指针(seekp、seekg、tellg、tellp)

在读写文件时,有时希望直接跳到文件中的某处开始读写,这就需要先将文件的读写指针指向该处,然后再进行读写。 ifstream 类和 fstream 类有 seekg 成员函数,可以设置文件读指针的位置; ofstream 类和 fstream 类有 seekp 成员函数,可以设置文件写指针的位置。

ifstream 类和 fstream 类还有 tellg 成员函数,能够返回文件读指针的位置; ofstream 类和 fstream 类还有 tellp 成员函数,能够返回文件写指针的位置。

//设置读写
ostream & seekp (int offset, int mode);
istream & seekg (int offset, int mode);
//返回读写
int tellg();
int tellp();

QQ图片20230530224309

 

#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
class CStudent
{
   public:
       char szName[20];
       int age;
};
int main()
{
   CStudent s;      
   fstream ioFile("students.dat", ios::in|ios::out);//用既读又写的方式打开
   if(!ioFile) {
       cout << "error" ;
       return 0;
  }
   ioFile.seekg(0,ios::end); //定位读指针到文件尾部,
                             //以便用以后tellg 获取文件长度
   int L = 0,R; // L是折半查找范围内第一个记录的序号
                 // R是折半查找范围内最后一个记录的序号
   R = ioFile.tellg() / sizeof(CStudent) - 1;
   //首次查找范围的最后一个记录的序号就是: 记录总数- 1
   do {
       int mid = (L + R)/2; //要用查找范围正中的记录和待查找的名字比对
       ioFile.seekg(mid *sizeof(CStudent),ios::beg); //定位到正中的记录
       ioFile.read((char *)&s, sizeof(s));
       int tmp = strcmp( s.szName,"Jack");
       if(tmp == 0) { //找到了
           s.age = 20;
           ioFile.seekp(mid*sizeof(CStudent),ios::beg);
           ioFile.write((char*)&s, sizeof(s));
           break;
      }
       else if (tmp > 0) //继续到前一半查找
           R = mid - 1 ;
       else  //继续到后一半查找
           L = mid + 1;
  }while(L <= R);
   ioFile.close();
   return 0;
}

 

 

 

 

资源来自 许多博客的资源 感谢他们的分享


md笔记下载地址
https://kxd.lanzoul.com/iBnXJ0xrgppc

posted @ 2023-05-23 22:33  大橘|博客  阅读(38)  评论(0)    收藏  举报