C++. 输入输出流IO

一、C++输入输出流IO

(一)基础知识概念

  1. 什么是“流”?
    流=字节流:①流向内存→输入流;②流向设备→输出流

  2. 流的3种类型(继承关系)
    (1)标准IO:标准的输入输出流
    (2)文件IO:文件输入输出流
    (3)串IO :字符串的输入输出流

  3. 流的4种状态
    在这里插入图片描述
    在这里插入图片描述

  4. 缓冲区
    (1)目的:解决内存和I/O设备速度不匹配
    (2)类型:全缓冲/满缓冲、行缓冲(endl)、不带缓冲(cerr)
    (3)缓冲区的刷新:
    ①程序正常结束的时候,会刷新缓冲区
    ②缓冲区满的时候,也会进行刷新
    ③可以手动刷新,endl、flush
    endl //刷新并换行
    flush //只刷新不换行
    ends //既不刷新,也不换行

二、文件IO

(一)文件输入流ifstream——输入进去才能读

//1. 空的
basic_ifstream();
//2. 绑定文件.txt 
explicit basic_ifstream( const char* filename,
                        std::ios_base::openmode mode = ios_base::in );
//3. C++字符串
explicit basic_ifstream( const std::string& filename,
                        std::ios_base::openmode mode = ios_base::in );
//explicit清楚的,明白的,清晰的,为了防止隐式转换的。
  1. explicit清楚的,明白的——为了防止隐式转换的
    (1)什么是隐式转换?
    如:
    ①Point pt2 = 10; // int类型的10 ====>Point(10,0)
    ②“hello,world”; //String s1 = ”hello,world” ====> String(“hello,world”)

(2)隐式转换→显示转换,在相应的位置上加“explicit”

(3)对于文件输入流而言
①若文件存在→打开成功;不存在→打开失败;
②文件流去读文件,以空格为分隔符

    1 #include <iostream>
    2 #include <fstream>//文件流
    3 
    4 using std::cout;
    5 using std::endl;
    6 using std::ifstream;
    7 using std::cerr;//不带缓冲
    8 using std::string;
    9 
   10 void test()
   11 {
   12     ifstream ifs("test.txt");//创建文件,打开文件
   13     //因为是文件流打开文件,有可能打开失败
   14     
   15     if(!ifs.good())//若状态不是正常态
   16     {
   17         //错误就不要用缓冲区了,即不用cout,直接用cerr就行
   18         cerr << "ifstream is not good" << endl;//文件没有打开
   19         return;//文件没有打开,就直接退出 
   20     }
   21     
   22     //文件流读文件——while循环,读到南里去呢?用string来接收
   23     string line;
   24     while(ifs >> line)//ifs.efo()不到文件末尾,就一直循环输入——可由可不有
   25     {
   26         cout << line;
   27     }                                                                                          
   28                            
   29                            
   30     ifs.close();//写完打开,就要写关闭
   31 }                          
   3233 int main(int argc, char **argv)
   34 {                          
   35     test();           
   36     return 0;         
   37 }                             

在这里插入图片描述

1. getline按行读取→能读到与源文件一样的东西

template< class CharT, class Traits, class Allocator >
std::basic_istream<CharT,Traits>& getline( std::basic_istream<CharT,Traits>& input,
                                           std::basic_string<CharT,Traits,Allocator>& str );

std::basic_istream& getline( std::basic_istream& input, std::basic_string& str );
//主要是将while循环的条件改变→getline(ifs,line),并改变line默认以空格分隔→用endl
    while(getline(ifs,line))//ifs.efo()不到文件末尾,就一直循环输入??可由可不有
   25     {
   26         cout << line << endl;                                                                                 
   27     }    
//完整版
   1 #include <iostream>
    2 #include <fstream>//文件流
    3 
    4 using std::cout;
    5 using std::endl;
    6 using std::ifstream;
    7 using std::cerr;//不带缓冲
    8 using std::string;
    9 
   10 void test()
   11 {
   12     ifstream ifs("test.txt");//创建文件,打开文件
   13     //因为是文件流打开文件,有可能打开失败
   14 
   15     if(!ifs.good())//若状态不是正常态
   16     {
   17         //错误就不要用缓冲区了,即不用cout,直接用cerr就行
   18         cerr << "ifstream is not good" << endl;//文件没有打开
   19         return;//文件没有打开,就直接退出 
   20     }
   21 
   22     //文件流读文件——while循环,读到南里去呢?用string来接收
   23     string line;
   24     while(getline(ifs,line))//ifs.efo()不到文件末尾,就一直循环输入——可由可不有
   25     {
   26         cout << line << endl;                                                                                 
   27     }                  
   28                        
   29                        
   30     ifs.close();//写完打开,就要写关闭
   31 }                      
   3233 int main(int argc, char **argv)
   34 {                      
   35     test();            
   36     return 0;          
   37 }   

在这里插入图片描述

2. 若想打印指定行,该怎么办?→ 先存,再打印

思路一:用数组存,再输出

    //文件流读文件??while循环,读到南里去呢?用string来接收
   23     string line[60];
   24     size_t idx = 0;//size_t是无符号整数
   25     while(getline(ifs,line[idx]))
   26     {
   27        ++idx;//这样每行对会存入对应的line[idx]
   28     }
   29 
   30     //第43行,下标42                                                                                          
   31     cout << "line[42] = " << line[42] << endl;
   32     
   33     ifs.close();//写完打开,就要写关闭
   34 }   

报错了 → 可以用容器vector来解决数组溢出的问题
在这里插入图片描述
思路二:用容器vector存,再输出
1° 容器是一种数据结构
2° 语法:vector<对象类型> vec; → vector<string> vec;
3° 输出时,用vector类中的成员函数push_back
4° 读43行,用vec[42](从0开始)

 1 #include <iostream>
    2 #include <fstream>//文件流
    3 #include <string>
    4 #include <vector>
    5 
    6 using std::cout;
    7 using std::endl;
    8 using std::ifstream;
    9 using std::cerr;//不带缓冲
   10 using std::string;
   11 using std::vector;
   12 
   13 void test()
   14 {
   15     string filename("test.txt");
   16     ifstream ifs(filename);//这样读的时候,从文本变成了C++字符串
   17     
   18     if(!ifs.good())//若状态不是正常态
   19     {
   20         //错误就不要用缓冲区了,即不用cout,直接用cerr就行
   21         cerr << "ifstream is not good" << endl;//文件没有打开
   22         return;//文件没有打开,就直接退出 
   23     }
   24     
   25     //文件流读文件——while循环,读到南里去呢?用string来接收
   26     string line;
   27     //创建一个对象,名为vec
   28     vector<string> vec;//容器中,存储string类型,<string>写在后面了,不同于int arr[]
   29 
   30     while(getline(ifs,line))
   31     {
   32         vec.push_back(line);
   33     }
   34 
   35     cout << "vec[42] = " << vec[42] << endl;                                                                                  
   36     ifs.close();//写完打开,就要写关闭
   38 }                          
   3940 int main(int argc, char **argv)
   41 {                          
   42     test();                
   43     return 0;              
   44 }                            

在这里插入图片描述

3. 若想用vector打印出文本.txt的全部内容

用vector对象中的size()函数,得知容器中元素的个数

   37     //打印文本全部内容
   38     for(size_t idx = 0; idx != vec.size(); ++idx)                                                             
   39     {
   40         cout << vec[idx] << endl;
   41     }

(二)文件输出流ofstream——输出了写

basic_ofstream();
explicit basic_ofstream( const char* filename,
                        std::ios_base::openmode mode = ios_base::out );
explicit basic_ofstream( const std::string& filename,
                        std::ios_base::openmode mode = ios_base::out );

对于文件输出流而言:
①当文件不存在的时候→创建文件
②当文件存在的时候 → 清空文件

1. 想把读ifs方式打开的文件,写到ofs的文件中去

  1. 怎么做呢?
    【注】ofs中,打开文件失败,则要在if语句中,把ifs的文件关掉
   25     string filename2("wd.txt");
   26     ofstream ofs(filename2);//这样写的时候,从文本变成了C++字符串
   27     if(!ofs.good())//若状态不是正常态
   28     {
   29         cerr << "ofstream is not good" << endl;
   30         ifs.close();
   31         return; 
   32     }
  1. 如何把ifs的内容,写到ofs中去呢?
    【思路】while循环
    1 #include <iostream>
    2 #include <fstream>//文件流
    3 #include <string>
    4 #include <vector>
    5        
    6 using std::cout;
    7 using std::endl;
    8 using std::ifstream;
    9 using std::ofstream;
   10 using std::cerr;//不带缓冲
   11 using std::string;
   12 using std::vector;
   13        
   14 void test()
   15 {   //以读的方式打开
   16     string filename("test.txt");
   17     ifstream ifs(filename);
   18     if(!ifs.good())
   19     {  
   20         cerr << "ifstream is not good" << endl;
   21         return; 
   22     }  
   23        
   24     //以写的方式打开
   25     string filename2("wd.txt");
   26     ofstream ofs(filename2);//这样写的时候,从文本变成了C++字符串
   27     if(!ofs.good())//若状态不是正常态
   28     {           
   29         cerr << "ofstream is not good" << endl;
   30         ifs.close();
   31         return; 
   32     }           
   33                 
   34     //文件流写文件——while循环,读到哪里去呢?用string来接收
   35     string line;
   36     while(getline(ifs,line))
   37     {
   38         ofs << line << endl;//写入ofstream的对象ofs中
   39     }                                                                                                          
   40 
   41     ifs.close();//记得关闭
   42     ofs.close();//记得关闭
   43 }   
   4445 int main(int argc, char **argv)
   46 {
   47     test();
   48     return 0;
   49 }  

在这里插入图片描述
… …

(三)文件输入输出流fstream

basic_fstream();
explicit basic_fstream(const char* filename,
                       std::ios_base::openmode mode = ios_base::in|ios_base::out );
explicit basic_fstream(const std::string& filename,
                       std::ios_base::openmode mode = ios_base::in|ios_base::out );

对于文件的输入输出流而言:
①当文件不存在 → 文件打开失败,要自己生成
在这里插入图片描述
②当文件存在 → 文件正常操作(要先生成,则存在文件)
在这里插入图片描述

1. 从键盘输入数据,通过fs写到文件中

   26     //1. 从键盘输入数据,通过fs写到文件中
   27     int number = 0;
   28     for(size_t idx = 0; idx != 5; ++idx)
   29     {
   30         cin >> number;//从键盘输入
   31         fs << number << " ";//通过fs写入
   32     }
   33     cout << endl;   

2. 通过fs进行读文件,将数据输出到屏幕

   34     //1. 从键盘输入数据,通过fs写到文件中
   35     for(size_t idx = 0; idx != 5; ++idx)
   36     {
   37         fs >> number;//通过fs读出
   38         cout << number << "";//输出到屏幕
   39     }

在这里插入图片描述
bug】可知,1 2 3 4 5成功写入到wuhan.txt中了,但是读出的时候全都是5
分析调代码】流的状态可能出bug了
∵已经成功输入1 2 3 4 5,故33行之前的代码没有问题
∴出现bug在34行后

   35     //2. 通过fs读出文件。并输出到屏幕
   36     for(size_t idx = 0; idx != 5; ++idx)
   37     {
   38         //调试
   39         cout << "fs.failbit = " << fs.fail() << endl
   40              << "fs.eofbit = " << fs.eof() << endl
   41              << "fs.goodbit = " << fs.good() << endl;                                                          
   42         fs >> number;//通过fs读出
   43         cout << number << " ";//输出到屏幕     
   44     }   
   45     cout << endl;    

在这里插入图片描述
(1)可知,第一轮的时候(001)是正常的;从第二轮开始出问题(110)
failbit=1、eofbit=1
(2)解决思路:文件指针到达了文件末尾,要偏移到文件头部
(3)解决操作:
· C语言:① 通过ftell()得到文件长度;②通过fseek()调整文件指针
· C++:① 通过tellg()获取文件指针位置;②通过seekg()偏移文件指针

注意

  1. 用文件输入流ifstream时:只能用“g”——记忆:我寄ig
  2. 用文件输出流ofstream时:只能用“p”——记忆:原批op
  3. 用文件IO流fstream时:都能用

掌握偏移seekp()的用法

  1. 绝对位置:fs.seekp(0);//直接移动到0处
  2. 相对位置:fs.seekp(-10,std::ios::end);//相对于尾部end,倒退10B
   35     //tellp/tellg(p:put读;g:get写)
   36     size_t len = fs.tellp();//求文件长度
   37     cout << "文件长度/偏移了len = " << len << "B" << endl;
   
   38     //seekp/seekg(p:put写;g:get读)
   39     fs.seekp(0);//绝对位置:移动文件指针于文件头部0
        /* fs.seekp(-10,std::ios::end); 相对位置 */
   40     len = fs.tellp();
   41     cout << "文件指针偏移了len = " << len << "B" << endl;                                                      
   42             

在这里插入图片描述

(四)文件模式

文件模式作用
in输入
out输出
☆app尾部追加(针对于写操作ofream,记忆:OP)
☆ate末尾(针对于读操作ifream)
trunc截断:若打开文件存在,则内容丢弃,其大小被截断为0
ate二进制,读写的文件为二进制形式

1. 文件输入(末尾ate)

   16 void test()
   17 {   //以读的方式打开
   18     ifstream ifs("test.txt",std::ios::in | std::ios::ate);//到文件末尾                                         
   19     if(!ifs.good())                                       
   20     {                                                     
   21         cerr << "fstream is not good" << endl;            
   22         return;                                           
   23     }                                                     
   24                                                           
   25     //输出ifs的位置/长度                                  
   26     cout << "ifs.tellg() = " << ifs.tellg() << endl;      
   27     ifs.close();                                                                                                        
   30 }                                                         
   3132 int main(int argc, char **argv)                           
   33 {                                                         
   34     test();                                               
   35     return 0;                                             
   36 }            

在这里插入图片描述

2. 文件输出(末尾app)

   32 void test2()
   33 {   //以写的方式打开
   34     ofstream ofs("wd.txt",std::ios::out | std::ios::app);//到文件末尾
   35     if(!ofs.good())
   36     {
   37         cerr << "ofstream is not good" << endl;
   38         return; 
   39     }
   40    
   41     //输出ofs的位置/长度
   42     cout << "ofs.tellp() = " << ofs.tellp() << endl;
   43    
  1. 因为文件存在,若34行如下 → ofstream会首先会清空文件
   34     ofstream ofs("wd.txt");

在这里插入图片描述

  1. 从末尾追加内容(app)
    在这里插入图片描述

三、字符串IO / 内存流 / 内存IO

istringstream字符串输入流
ostringstream字符串输出流
stringstream字符串输入输出流
//委托构造函数
basic_ostringstream() : basic_ostringstream(ios_base::out) { }

explicit basic_ostringstream( ios_base::openmode mode = ios_base::out );

explicit basic_ostringstream( ios_base::openmode mode );

explicit basic_ostringstream( const std::basic_string<CharT,Traits,Allocator>& str,
                              ios_base::openmode mode = ios_base::out );

(一)把int转换为字符串string

    1 #include <iostream>
    2 #include <sstream>
    3 #include <string>
    4 
    5 using std::cout;
    6 using std::endl;
    7 using std::ostringstream;
    8 using std::istringstream;
    9 using std::stringstream;
   10 using std::string;
   11 
   12 string int2String(int value)
   13 {
   14     ostringstream oss; //通过ostring创建空对象(中转)
   15     oss << value;//把值输入进去
   16 
   17     return oss.str(); //获取底层的字符串
   18 }
   19 
   20 void test()
   21 {
   22     int number = 10;
   23     string s1 = int2String(number);
   24     cout << "s1 = " << s1 << endl;                                                                             
   25 }                           
   26                             
   27 int main(int argc, char **argv)
   28 {                           
   29     test();                 
   30     return 0;               
   31 }  

【注意】用函数str(); //获取底层的字符串

以字符串形式输出了:
在这里插入图片描述

(二)先通过stringstram得到字符串,然后可拆开

   1 #include <iostream>                                                                                            
    2 #include <sstream>
    3 #include <string>
    4 
    5 using std::cout;
    6 using std::endl;
    7 using std::ostringstream;
    8 using std::istringstream;
    9 using std::stringstream;
   10 using std::string;
  
   27 void test2()
   28 {
   29     int number1 = 10;
   30     int number2 = 20;
   31     stringstream ss;
   32     //先输出到ss里面
   33     ss << "number1= " << number1
   34        << " ,number2= " << number2 << endl;
   35     string s1 = ss.str();
   36     cout << s1 << endl;
   37     
   38     string key;
   39     int value;
   40     while(ss >> key >> value)
   41     {//ss现在是number1= 10,number2= 20
   42      //ss把字符串部分给key,int部分给value————利用了空格
   43         cout << key << "------->" << value << endl;
   44     }
   45 }                          
   4647 int main(int argc, char **argv)
   48 {                          
   49     test2();               
   50     return 0;              
   51 }  

在这里插入图片描述

(三)拆开字符串部分和数字部分

my.Conf内容如下:
在这里插入图片描述

    1 #include <iostream>                                                                                                               
    2 #include <sstream>
    3 #include <string>
    4 #include <fstream>
    5 
    6 using std::cout;
    7 using std::endl;
    8 using std::cerr;
    9 using std::ifstream;
   10 using std::ostringstream;
   11 using std::istringstream;
   12 using std::stringstream;
   13 using std::string;
 
   50 void readConfig(const string &filename)
   51 {
   52     ifstream ifs(filename);
   53     if(!ifs)//!ifs.good()
   54     {
   55         cerr << "open " << filename << "error!" << endl;
   56         return;
   57     }
   58 
   59     string line;
   60     while(getline(ifs,line))
   61     {
   62         istringstream iss(line);
   63         string key,value;
   64         iss >> key >> value;//拆分
   65 
   66         cout << key << "      " << value << endl;
   67     }
   68 
   69 
   70     ifs.close();
   71 }
   72 
   73 void test3()
   74 {
   75     readConfig("my.Config");
   76 }
   7778 int main(int argc, char **argv)
   79 {
   80     test3();
   81     return 0;
   82 }

在这里插入图片描述

四、容器vector的原理

(一)vec.size()和vec.capacity()

vec.size()vec.capacity()
容器中,元素的个数容器的大小

若不用push_back()赋值,则容器大小初始化为0

    1 #include <iostream>
    2 #include <vector>
    3 
    4 using std::cout;
    5 using std::endl;
    6 using std::vector;
    7 //打印vector的容量和元素个数
    8 void printVectorCapacity(const vector<int> &vec)
    9 {
   10     cout << "容器的容量大小capacity = " << vec.capacity() << endl;
   11     cout << "容器中元素个数size = " << vec.size()<< endl;
   12 }
   13 
   14 void test()
   15 {
   16     vector<int> vec;//容器里面存int类型的数据
   17     printVectorCapacity(vec);//若不赋值,初始化为0
   18    
   19     cout << endl;
   20     vec.push_back(1);
   21     printVectorCapacity(vec);
   22 
   23     cout << endl;
   24     vec.push_back(2);
   25     printVectorCapacity(vec);
   26     
   28     cout << endl;
   29     vec.push_back(3);
   30     printVectorCapacity(vec);
   32 
   33     cout << endl;
   34     vec.push_back(4);
   35     printVectorCapacity(vec);
   36   
   38     cout << endl;
   39     vec.push_back(5);
   40     printVectorCapacity(vec);
   41 
   43     cout << endl;
   44     vec.push_back(6);                                                                                          
   45     printVectorCapacity(vec);
   46 }   
   47 
   48 int main(int argc, char **argv)
   49 {
   50     test();
   51     return 0;
   52 } 

![在这里插入图片描述](https://img-blog.csdnimg.cn/3823a9a52c9f4b9eace59db61da7d29b.png

  1. 底层的扩容原理:当size()==capacity(),会按照2*capacity()扩容,而扩容,是连续重新申请分配
  2. 新申请的空间在新的位置,然后再将旧空间的数据——拷贝—→到新空间,然后将旧空间回收

(二)其他vector对象,常用成员函数的用法

成员函数作用
push_back()插入新元素,插入位置:当前最后一个元素的下一个元素
pop_back()移除最后一个元素
clear()清空所有元素
empty()判断vector是否为空,如果返回true为空
erase()删除指定元素
//在vec尾部直接添加10
vector<int> vec;
vec.push_back(10);

//在vec尾部间接添加10
int num = 10;
vector<int> vec;
vec.push_back(num);

//在string字符串最后插入一个字符
string str;
str.push_back('d');
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值