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

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

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

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

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

  每种语言系统都会提供IO操作的类库,用于对预定义类型数据进行输入输出的操作。C++也是如此,它是以字节流的形式实现的。在输入操作时,字节流从输入设备(键盘、磁盘)流向内存;在输出操作时,字节流由内存流向输出设备(显示器、打印机);字节流可以是ASCII字符、二进制数据、图形图像、音频视频等信息。文件和字符串也可以看成是有序的字节流,又称为文件流和字符串流。C++的编译系统自带一个面向对象的输入输出软件包,即IO流类库。库中各种类的声明都被包含在相应的头文件中,比如之前经常用到的头文件iostream,其中使用的cin\cout都是常用的流对象,用于对标准设备的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++!\n";
17 
18     char ch;
19     while (cin.get(ch))
20     {
21         if (ch == '\n')
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);//读到'\n'终止
18     cout << str << endl;
19 
20     char rch;
21     while (rfile.get(rch))//文件指针指向字符‘\n’的下一个
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.\n", 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

  

 

posted @ 2015-03-24 10:03  峰子_仰望阳光  阅读(543)  评论(0编辑  收藏  举报