• 文件读写及字符串与整数的相互转换


      对于C++中的IO操作,博主nbkyzj的三篇文章概括的特别详细,非常值得参考。这三篇文章是:

      C++之标准设备IO操作流
      C++之预定义类型IO格式控制
      C++之文件IO操作流

      下文将会部分参考自这三篇文章。

      1. C++之标准设备IO操作流

      每种语言系统都会提供IO操作的类库,用于对预定义类型数据进行输入输出的操作。C++也是如此,它是以字节流的形式实现的。在输入操作时,字节流从输入设备(键盘、磁盘)流向内存;在输出操作时,字节流由内存流向输出设备(显示器、打印机);字节流可以是ASCII字符、二进制数据、图形图像、音频视频等信息。文件和字符串也可以看成是有序的字节流,又称为文件流和字符串流。C++的编译系统自带一个面向对象的输入输出软件包,即IO流类库。库中各种类的声明都被包含在相应的头文件中,比如之前经常用到的头文件iostream,其中使用的cincout都是常用的流对象,用于对标准设备的IO操作。还有用于用户文件管理IO操作的fstream头文件(磁盘文件的操作),用于字符串流的IO操作的strstream头文件(内存字符流的操作),以及iomanip头文件用于输入输出的格式控制。

      在IO流类库中包含以下几个常用的流类:

      

      ios是抽象基类,类istream和ostream是单继承于ios,而类iostream是通过多继承于类istream和类ostream。ios除了派生出istream和ostream还派生出fstreambase文件流类和strstreambase串流类,而该4类又派生出ifstream、ofstream、istrstream、ostrstream,以及fstream和strstream。

      在C++中除了上述提到过的预定义流对象cout和cin外,还有非缓冲标准出错流对象cerr和缓冲标准出错流对象clog,它们都是来自于ostream类的对象,用于输出错信息。cerr和clog之间的不同之处在于cerr是不经过缓冲区直接向显示器输出有关信息,而clog则是先把信息放在缓冲区,缓冲区满后或遇上endl时向显示器输出。

      2. C++之文件IO操作流

      文件是指存放在外部介质上的数据的集合。大家都知道操作系统是以文件为单位来对数据进行管理的。因此如果你要查找外部介质的数据,则先要按文件名找到指定文件,然后再从文件中读取数据,如果要把数据存入外部介质中,如果没有该文件,则先要建立文件,再向它输入数据。由于文件的内容千变万化,大小各不相同,为了统一处理,在C++中用文件流的形式来处理,文件流是以外存文件为输入输出对象的数据流。输出文件流表示从内存流向外存文件的数据,输入文件流则相反。根据文件中数据的组织形式,文件可分为两类:文本文件和二进制文件。文本文件又称为ASCII文件,它的每个字节存放一个ASCII码,代表一个字符。二进制文件则是把内存中的数据,按照其在内存中的存储形式原样写在磁盘上存放。比如一个整数20000,在内存中占两个字节,而按文本形式输出则占5个字节。因此在以文本形式输出时,一个字节对应一个字符,因而便于字符的输出,缺点则是占用存储空间较多。用二进制形式输出数据,节省了转化时间和存储空间,但不能直接以字符的形式输出。

       2.1 文件打开

      在C++中对文件进行操作分为以下几个步骤:

      1)建立文件流对象;

      2)打开或建立文件;

      3)进行读写操作;

      4)关闭文件。

      用于文件IO操作的流类主要有三个fstream(输入输出文件流),ifstream(输入文件流)和ofstream(输出文件流);而这三个类都包含在头文件fstream中,所以程序中对文件进行操作必须包含该头文件。

      首先建立流对象,然后使用文件流类的成员函数open打开文件,即把文件流对象和指定的磁盘文件建立关联。成员函数open的一般形式为:

      文件流对象.open(文件名,使用方式)

      其中文件名可以包括路径(如:e:c++file.txt),如果缺少路径,则默认为当前目录。使用方式则是指文件将被如何打开。以下就是文件的部分使用方式,都是ios基类中的枚举类型的值:

      

      此外打开方式有几个注意点:

      1)因为nocreate和noreplace,与系统平台相关密切,所以在C++标准中去掉了对它的支持。

      2)每一个打开的文件都有一个文件指针,指针的开始位置由打开方式指定,每次读写都从文件指针的当前位置开始。每读一个字节,指针就后移一个字节。当文件指针移到最后,会遇到文件结束符EOF,此时流对象的成员函数eof的值为非0值,表示文件结束。

      3)用in方式打开文件只能用于输入数据,而且该文件必须已经存在。

      4)用app方式打开文件,此时文件必须存在,打开时文件指针处于末尾,且该方式只能用于输出。

      5)用ate方式打开一个已存在的文件,文件指针自动移到文件末尾,数据可以写入到其中。

      如果文件需要用两种或多种方式打开,则用"|"来分隔组合在一起。

      除了用open成员函数打开文件,还可以用文件流类的构造函数来打开文件,其参数和默认值与open函数完全相同。比如:文件流类 stream(文件名,使用方法);如果文件打开操作失败,open函数的返回值为0,用构造函数打开的话,流对象的值为0。所以无论用哪一种方式打开文件,都需要在程序中测试文件是否成功打开。

       在每次对文件IO操作结束后,都需要把文件关闭。那么就需要用到文件流类的成员函数close,一般调用形式:流对象.close()。关闭实际上就是文件流对象和磁盘文件失去关联。

       2.2 文件读写

      流类库中的IO操作<<、>>、put、get、getline、read和write都可以用于文件的输入输出。

      文件写:

     1 #include <iostream>
     2 #include <fstream>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     //打开文件
     8     ofstream file("file.txt", ios::out | ios::ate);
     9     if (!file)
    10     {
    11         cout << "不可以打开文件" << endl;
    12         exit(1);
    13     }
    14 
    15     //写文件
    16     file << "hello c++!
    ";
    17 
    18     char ch;
    19     while (cin.get(ch))
    20     {
    21         if (ch == '
    ')
    22             break;
    23         file.put(ch);
    24     }
    25 
    26     //关闭文件
    27     file.close();
    28 
    29     return 0;
    30 }
    WriteFile

      文件读:

     1 #include <iostream>
     2 #include <fstream>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     //打开文件
     8     ifstream rfile("file.txt", ios::in);
     9     if (!rfile)
    10     {
    11         cout << "不可以打开文件" << endl;
    12         exit(1);
    13     }
    14 
    15     //读文件
    16     char str[100];
    17     rfile.getline(str, 100);//读到'
    '终止
    18     cout << str << endl;
    19 
    20     char rch;
    21     while (rfile.get(rch))//文件指针指向字符‘
    ’的下一个
    22     {
    23         cout.put(rch);
    24     }
    25 
    26     cout << endl;
    27 
    28     //关闭文件
    29     rfile.close();
    30 
    31     return 0;
    32 }
    ReadFile

      3. 字符串与整数的相互转换

      这一部分主要参考自一博文

       3.1 整数转换为字符串

        1)利用itoa

     1 #include <iostream>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     // char *itoa( int value, char *string,int radix);
     7     // 原型说明:
     8     // value:欲转换的数据。
     9     // string:目标字符串的地址。
    10     // radix:转换后的进制数,可以是10进制、16进制等。
    11     // 返回指向string这个字符串的指针
    12 
    13     int i = 30;
    14     char c[8];
    15     itoa(i, c, 16);
    16     cout << c << endl; // 1e
    17 
    18     return 0;
    19 }
    View Code

      注意:itoa并不是一个标准的C函数,也不是C++一部分。只有部分编译器(如VS)支持。如果要想跨平台,要得sprintf。

        2)利用sprintf

     1 #include <iostream>
     2 #include <stdio.h>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     // int sprintf( char *buffer, const char *format, [ argument] … );
     8     // 参数列表
     9     // buffer:char型指针,指向将要写入的字符串的缓冲区。
    10     // format:格式化字符串。
    11     // [argument]...:可选参数,可以是任何类型的数据。
    12     // 返回值:字符串长度(strlen)
    13 
    14     int i = 30;
    15     char c[8];
    16     int length = sprintf(c, "%05X", i);
    17     cout << c << endl; // 0001E
    18 
    19     return 0;
    20 }
    View Code

      3)利用stringstream

     1 #include <iostream>
     2 #include <sstream>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     int i = 30;
     8     stringstream ss;
     9     ss << i;
    10     string s1 = ss.str();
    11     cout << s1 << endl; // 30
    12 
    13     string s2;
    14     ss >> s2;
    15     cout << s2 << endl; // 30
    16 
    17     return 0;
    18 }
    View Code

      stringstream可以吞下不同的类型,根据s2的类型,然后吐出不同的类型。

      4)利用使用boost库中的lexical_cast

     1 #include <iostream>
     2 #include <boost/lexical_cast.hpp>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     int i = 30;
     8     string s = boost::lexical_cast<string>(i);
     9     cout << s << endl; // 30
    10 
    11     return 0;
    12 }
    View Code

       3.2 字符串转为整数

      1)利用strtol(string to long)

     1 /* strtol example */
     2 #include <stdio.h>      /* printf */
     3 #include <stdlib.h>     /* strtol */
     4 
     5 int main()
     6 {
     7     // long int strtol(const char* str, char** endptr, int base);
     8 
     9     char szNumbers[] = "2001 60c0c0 -1101110100110100100000 0x6fffff";
    10     char * pEnd;
    11     long int li1, li2, li3, li4;
    12     li1 = strtol(szNumbers, &pEnd, 10);
    13     li2 = strtol(pEnd, &pEnd, 16);
    14     li3 = strtol(pEnd, &pEnd, 2);
    15     li4 = strtol(pEnd, NULL, 0);
    16     printf("The decimal equivalents are: %ld, %ld, %ld and %ld.
    ", li1, li2, li3, li4);
    17 
    18     return 0;
    19 }
    View Code

      2)利用stringstream

     1 #include <iostream>
     2 #include <sstream>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     string s = "17";
     8 
     9     stringstream ss;
    10     ss << s;
    11 
    12     int i;
    13     ss >> i;
    14     cout << i << endl; // 17
    15 
    16     return 0;
    17 }
    View Code

      stringstream可以吞下任何类型,根据实际需要吐出不同的类型。

      3)利用boost库中的lexical_cast

     1 #include <iostream>
     2 #include <boost/lexical_cast.hpp>
     3 using namespace std;
     4 
     5 int main()
     6 {
     7     string s = "17";
     8     int i = boost::lexical_cast<int>(s);
     9     cout << i << endl; // 17
    10 
    11     return 0;
    12 }
    View Code

      4. 数据文件读写

      比较常见的是对整数数据的读写,程序如下:

     1 #include <iostream>
     2 #include <fstream>
     3 #include <string>
     4 #include <sstream>
     5 #include <math.h>
     6 using namespace std;
     7 
     8 int main()
     9 {
    10     // *************************** Write File *************************** // 
    11     // Open file
    12     ofstream wfile("file.txt", ios::out);
    13     if (!wfile)
    14     {
    15         cout << "The file can not be opened!" << endl;
    16         exit(1);
    17     }
    18 
    19     for (int i = 0; i < pow(2, 16); i++)
    20     {
    21         stringstream ss;
    22         ss << i;
    23         string str = ss.str();
    24         wfile << str;
    25         wfile << endl;
    26     }
    27 
    28     // Close the file
    29     wfile.close();
    30 
    31     // *************************** Read File *************************** //
    32     // Open file
    33     ifstream rfile("file.txt", ios::in);
    34     if (!rfile)
    35     {
    36         cout << "The file can not be opened!" << endl;
    37         exit(1);
    38     }
    39 
    40     string line;
    41     int num;
    42     while (getline(rfile, line))
    43     {
    44         // cout << line << endl;
    45         stringstream ss;
    46         ss << line;
    47         ss >> num;
    48         cout << num << endl;
    49     }
    50 
    51     // Close the file
    52     rfile.close();
    53 
    54     return 0;
    55 }
    View Code

      

  • 相关阅读:
    《穿越时空的git》之创建版本库和常用命令操作
    全链路灰度在数据库上我们是怎么做的?
    菜鸟 CPaaS 平台微服务治理实践
    与字节、小米、移动云等企业一起揭秘 RocketMQ 实践之道
    2022 云原生编程挑战赛火热报名中!看导师如何拆解 Serverless 赛题?
    阿里云消息队列 Kafka消息检索实践
    阿里云 MSE 支持 Go 语言流量防护
    不懂就问,快速成为容器服务进阶玩家!
    有奖征文 | 2022 云原生编程挑战赛征稿活动开启!
    发评测赢好礼 | Serverless 函数计算征集令
  • 原文地址:https://www.cnblogs.com/xiehongfeng100/p/4361954.html
Copyright © 2020-2023  润新知