文件利用、流对象示例

打印 上一主题 下一主题

主题 1766|帖子 1766|积分 5298

一、向文件中写入内容

  我们现在桌面创建一个.txt文件,将里面的内容设置为abcdefghijklmn 
  如果想要向这个文件中写入内容,我们需要借助文件流对象建立起文件与步调之间的接洽。
  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. using namespace std;
  5. int main()
  6. {
  7.         ofstream outFile("C:\Users\31604\Desktop\example.txt", ios::app);
  8.         if (outFile.is_open())
  9.         {
  10.                 outFile << " opqrst " << endl;
  11.                 outFile.close();
  12.         }
  13.         else
  14.         {
  15.                 throw runtime_error("Fail to open file");
  16.                 cout << endl;
  17.         }
  18.         return 0;
  19. }
复制代码
这么写会报错,因为在C++中,\是转义字符,如果只使用单个反斜杠,会报错:通用字符名的格式不正确。
  解决方法有两个:
  方法一:加两个反斜杠,就代表我们真的想写入反斜杠。
  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. using namespace std;
  5. int main()
  6. {
  7.         ofstream outFile("C:\\Users\\31604\\Desktop\\example.txt", ios::app);
  8.         if (outFile.is_open())
  9.         {
  10.                 outFile << " opqrst " << endl;
  11.                 outFile.close();
  12.         }
  13.         else
  14.         {
  15.                 throw runtime_error("Fail to open file");
  16.                 cout << endl;
  17.         }
  18.         return 0;
  19. }
复制代码
方法二:使用原始字符串字面量。从 C++11 开始,可以使用原始字符串字面量,在字符串前加上R,并用 (  ) 括起字符串内容,如许字符串中的反斜杠就不会被当作转义字符处置惩罚。代码如下:
  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. using namespace std;
  5. int main()
  6. {
  7.     ofstream outFile(R"(C:\Users\31604\Desktop\example.txt)", ios::app);
  8.     if (outFile.is_open())
  9.     {
  10.         outFile << " opqrst " << endl;
  11.         outFile.close();
  12.     }
  13.     else
  14.     {
  15.         throw runtime_error("Fail to open file");
  16.         cout << endl;
  17.     }
  18.     return 0;
  19. }
复制代码
我们此时再打开这个example.txt文件,就会发现里面的内容变成了如许:
  

  说明成功写入。
  需要留意的是,当我们在 IDE中运行步调时,步调的当前工作目录不肯定是桌面。所以它大概尝试在其他目录中创建或追加到名为example.txt的文件,而不是桌面上的那个文件。
  ios::app是什么?
  ofstream(输出文件流)对象的构造函数有多个重载版本,以下是两个常见的版本:
 
  1. ofstream(const char* filename);//只指定文件路径
复制代码
  1. ofstream(const char* filename,ios_base::openmode mode);//指定文件路径和打开方式
复制代码
ios_base:penmode是一个位掩码范例,定义了多种打开模式,常见的有:
  1. ios_base::app    追加模式,写入数据时将数据追加到文件末尾
  2. ios_base::ate    文件打开后立即将文件指针移动到文件末尾
  3. ios_base::in     以读模式打开文件(通常用于ifstream)
  4. ios_base::out    以写模式打开文件(默认覆盖写入)
  5. ios_base::trunc  如果文件存在,截断文件,即删除原有内容  
复制代码
这些模式可以通过按位或(|)运算符组合使用。比方:
  1. #include <iostream>
  2. #include <fstream>
  3. int main()
  4. {
  5.     // 使用 ios_base 设置文件打开模式
  6.     std::ofstream outFile("example.txt", std::ios_base::out | std::ios_base::trunc);
  7.     if (outFile.is_open())
  8.     {
  9.         // 使用 ios_base 设置格式标志
  10.         outFile << std::ios_base::hex << 100 << std::endl;
  11.         // 以十六进制输出 100,输出结果为 64
  12.         outFile.close();
  13.     }
  14.     return 0;
  15. }
复制代码
追问:ios_base和ios有什么区别?
  ios_base类是ios类的父类,ios类是istream类和ostream类的父类。
  ios_base类定义了一些基本的流利用特性和常量,好比格式标志(控制输入输出的格式)、流利用符等。当涉及到文件打开模式、格式标志(比方控制数字输出的进制)这些基础的流利用特性常量时,要用ios_base.比方ios_base::in(用于输入文件流打开方式)、ios_base::hex(设置十六进制输出格式)等。
  而当我们需要处置惩罚流的状态管理,好比判断流是否处于良好状态(ios::good())、是否到达文件末尾(ios::eof()),或者设置和获取流的错误状态标志等利用时,就使用ios类及其派生类(istream\ostream等)
  如果是进行输入输出利用,好比从输入流读取数据,或者向输出流写入数据,则使用istream和ostream及其派生类(ifstream\ofstream等)。
  举一个使用ios管理流状态的例子:
 
  1. #include <iostream>
  2. #include <sstream>
  3. int main()
  4. {
  5.     std::string str = "123";
  6.     std::istringstream iss(str);
  7.     int num;
  8.     iss >> num;
  9.     if (iss.good())
  10.     {
  11.         std::cout << "成功读取数字: " << num << std::endl;
  12.     }
  13.     else if (iss.eof())
  14.     {
  15.         std::cout << "到达流末尾,但可能读取不完整。" << std::endl;
  16.     }
  17.     else
  18.     {
  19.         std::cout << "读取失败。" << std::endl;
  20.     }
  21.     return 0;
  22. }
复制代码
需要留意的是,ios类尽管确实是从ios_base类public继承而来的,但那些用于文件打开模式的常量(ios_base:ut、ios_base::trunc等),它们并不是以通例的成员变量或成员函数的访问控制方式来决定是否能在子类ios中直接使用。这些常量是在ios_base的作用域内定义的枚举范例成员。虽然ios继承了ios_base的成员,但在 C++ 语法规则里,要使用这些枚举常量,必须通过定义它们的类名(也就是ios_base)来限定访问,即便继承是public的。
  

  二、将文件中的内容读入字符串中

  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. using namespace std;
  5. int main()
  6. {
  7.         ifstream inFile(R"(C:\Users\31604\Desktop\example.txt)");
  8.         if (inFile.is_open())
  9.         {
  10.                 string line;
  11.                 while (getline(inFile, line))
  12.                 {
  13.                         cout << line << endl;
  14.                 }
  15.                 inFile.close();
  16.         }
  17.         else
  18.         {
  19.                 cerr << "无法打开文件" << endl;
  20.         }
  21.         return 0;
  22. }
复制代码
运行结果:
  

  对getline()不熟悉的,请参阅:对流对象的明白-CSDN博客
  我们还可以指定分隔符,不肯定读到默认的换行符,代码如下:
  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. using namespace std;
  5. int main()
  6. {
  7.         ifstream inFile(R"(C:\Users\31604\Desktop\example.txt)");
  8.         if (inFile.is_open())
  9.         {
  10.                 string line;
  11.                 while (getline(inFile, line,'g'))
  12.                 {
  13.                         cout << line << endl;
  14.                 }
  15.                 inFile.close();
  16.         }
  17.         else
  18.         {
  19.                 cerr << "无法打开文件" << endl;
  20.         }
  21.         return 0;
  22. }
复制代码
运行结果:
  

  也就是说,在重载版本getline(istream&is,string&str,char ch)中,ch作为分隔符,充当了原本换行符的角色。换行后,getline()会继承读入,会覆盖原有str中的内容,所以输出结果就会如上所示。
  三、使用istringstream读取字符串中的内容

  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. #include<string>
  5. using namespace std;
  6. int main()
  7. {
  8.         string str = "123 45.6 hello";
  9.         istringstream iss(str);//构造函数
  10.         int int_val;
  11.         double double_val;
  12.         string string_val;
  13.         iss >> int_val;
  14.         iss >> double_val;
  15.         iss >> string_val;
  16.         cout << "读取的整数:" << int_val << endl;
  17.         cout << "读取的双精度浮点数:" << double_val << endl;
  18.         cout << "读取的字符串:" << string_val << endl;
  19.         return 0;
  20. }
复制代码
运行结果:
  

  如果数据范例和读取的顺序不一致,比方下面如许:
  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. #include<string>
  5. using namespace std;
  6. int main()
  7. {
  8.         string str = "123 four 78.9 hello";
  9.         istringstream iss(str);//构造函数
  10.         int int_val;
  11.         double double_val;
  12.         string string_val;
  13.         iss >> int_val;
  14.         iss >> double_val;
  15.         iss >> string_val;
  16.         cout << "读取的整数:" << int_val << endl;
  17.         cout << "读取的双精度浮点数:" << double_val << endl;
  18.         cout << "读取的字符串:" << string_val << endl;
  19.         return 0;
  20. }
复制代码
会显示 读取的双精度浮点数为0,读取的字符串为空
  因为从输入流iss读取数据时,它盼望读取一个符合双精度浮点数格式的值。然而在读取完整数123后,下一个非空缺字符序列是"four",这不是一个有效的双精度浮点数表现。
  
  当istringstream尝试将"four"转换为双精度浮点数时,转换失败。这会导致输入流进入错误状态(failbit被设置),而且后续从该流的读取利用(如iss>>string_val;)将不再进行,因为一旦流处于错误状态,它会忽略后续的读取请求。
  要解决这个问题,可以在每次读取利用后查抄流的状态,以确保读取成功。比方:
  1. #include <iostream>
  2. #include <sstream>
  3. #include <string>
  4. using namespace std;
  5. int main()
  6. {
  7.     string str = "123 four 78.9 hello";
  8.     istringstream iss(str);
  9.     int int_val;
  10.     double double_val;
  11.     string string_val;
  12.     if (!(iss >> int_val))
  13.     {
  14.         cerr << "无法读取整数" << endl;
  15.         return 1;
  16.     }
  17.     if (!(iss >> double_val))
  18.     {
  19.         // 跳过 "four" 并尝试重新读取双精度浮点数
  20.         string skip;
  21.         iss >> skip;
  22.         if (!(iss >> double_val))
  23.         {
  24.             cerr << "无法读取双精度浮点数" << endl;
  25.             return 1;
  26.         }
  27.     }
  28.     if (!(iss >> string_val))
  29.     {
  30.         cerr << "无法读取字符串" << endl;
  31.         return 1;
  32.     }
  33.     cout << "读取的整数:" << int_val << endl;
  34.     cout << "读取的双精度浮点数:" << double_val << endl;
  35.     cout << "读取的字符串:" << string_val << endl;
  36.     return 0;
  37. }
复制代码
四、使用ostringstream向字符串中写入内容

  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. #include<string>
  5. using namespace std;
  6. int main()
  7. {
  8.         int num = 100;
  9.         double pi = 3.14159;
  10.         string name = "kvermouth";
  11.         ostringstream oss;
  12.         oss << "数字:" << num << ",圆周率:" << pi << ",名字:" << name;//写入内容
  13.         string res = oss.str();//oss.str()用于获取最终生成的字符串
  14.         cout << res << endl;
  15.         return 0;
  16. }
复制代码
运行结果:
  

  五、使用stringstream,既能读,又能写

  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. #include<string>
  5. using namespace std;
  6. int main()
  7. {
  8.         stringstream ss;
  9.         int num = 66;
  10.         string str = "world";
  11.         //写入
  12.         ss << "Hello," << num << " " << str;
  13.         //读取
  14.         string new_str;
  15.         ss >> new_str;
  16.         cout << new_str << endl;
  17.        
  18.         return 0;
  19. }
复制代码
运行结果:
  

  为什么输出的结果不是Hello,66 world呢?
  

  • 首先,代码中创建了一个stringstream对象ss,然后将数据写入这个流中。执行    ss << "Hello," << num << " " << str;时,stringstream会按照顺序将"Hello"、整数66(转换为字符串形式"66")、一个空格字符" "以及字符串"world"毗连起来写入流中。此时stringstream内部维护的缓冲区内容大致为"Hello,66 world"
  • 接着执行ss>>new str;  stringstream从其缓冲区读取数据时,会以空缺字符(空格、制表符、换行符等)作为分隔符。所以它会读取到第一个空缺字符(这里是空格)之前的内容,也就是"Hello,66"并将其存储到new_str中。
  如果我们想要读取整个字符串的内容,可以使用getline()
  1. #include<iostream>
  2. #include<fstream>
  3. #include<sstream>
  4. #include<string>
  5. using namespace std;
  6. int main()
  7. {
  8.         stringstream ss;
  9.         int num = 66;
  10.         string str = "world";
  11.         //写入
  12.         ss << "Hello," << num << " " << str;
  13.         //读取
  14.         string new_str;
  15.         getline(ss, new_str);
  16.         cout << new_str << endl;
  17.        
  18.         return 0;
  19. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

吴旭华

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表