C++ 文件和流操作(Files and streams)
2014-07-02 16:20
363 查看
大部分情况下, 我们的程序的输入数据(input)仅可以来自于keyboard输入, 程序的输出也只是screen的console,。但是其实我们的program的输入输出
不应该只是限于keyboard 和screen这两种input 和output devices.。 试想一下, 如果我们的程序需要处理大量的数据的时候, 如果仅仅依靠键盘来手写输入,
那么运行的效率将会是何其的低。 同理, 如果我们仅仅将处理后的大量数据送到屏幕上显示, 二不去保存这些大量的数据, 当我们关掉电脑的时候,
所有的结果数据都想会消失(因为我们的数据在内存中)。这或许就是C++ 文件流处理的motivation。
所以 ,为了应对上面关于输入输出的两个challenges, 我们需要我们的数据存放在一些secondary storage device中, 这些device通常是magnetics
tapes, 或者disc(磁盘中)。 这样在必要的时候, 们就可以通过编写program 创建, 修改, 存取(access)我们的数据。 为了实现这些目的, 我们的数据
以文件(files)的数据结构(data structures)的形式 packageed up on storage devices。
我们可以将文件看成是由一个线性字符序列(a linear sequence of characters)的数据结构组织的。 举一个例子, 下面文件(截图)的存储形式可能看成是是如下形式:
存储方式:
Streams
在我们用C++ 处理文件的之前, 我们已经对流有过了解了。 我们可以将streams 想象成数据从senders 到 receivers 的一个通道(channel)。
就目前而言, 我们将只允许我们的流是单方向的运动。 数据可以从程序输出的输出流(例如程序将处理结果从到显示器显示(output stream), 或者是从到磁盘存储起来
等等)。 亦或是数据从键盘, 或者磁盘中送到程序进行处理的输入流(input stream) .。 NOTE: 输入流还是输出流是站在program的角度看的。
举个例子, 程序开始的时候, 标准输入流'cin'连接到键盘等待用户输入。 输出流'cout' 连接到显示器以便将程序的结果显示在屏幕上。
事实上, 输入流cin 和输出流cout 是stream(流类)objects(对象)。所以这也是OOP的一部分。
在处理文件流的时候, 我们需要一个列举出了关于定义了文件的输入流和输出流的一些operations, 该头文件的名字是“fstream”。 所以我们在编写此类程序之前,
必须在程序之前添加如下的指导语句:
#include <fstream>
Creating Streams
当我们想要在程序中使用文件的输入流和输出流, 第一步就是创建文件流。 ifstream class 用于创建输入流的对象, ofstream 用于创建输出流的对象。
如下:
ifstream in_stream;
ofstream out_stream;
Connecting and Disconnecting Streams to files
创建完了流对象之后, 接下来就是使用openc() 成员函数去把文件与流对象连接起来。 成员函数open() 对于ifstreams对象和ofstream的对象的作用效果
是不同, 也就是说openc() function是porlymorphic的(多态的)。
(1)将ifstream 对象in_stream 与文件“Lecture_4” 连接起来。
in_stream.open("Lecture_4");
可以用下图形象的表示:
将输出文件流ofstream的对象“out_stream” 与文件“Lecture_4”连接起来:
out_stream.open(“Lecture_4”);
注意, 尽管将out_stream 和 “Lecture_4”连
接起来, 但是It also delete the previous contents of the file, ready for new content。 用下图形象的表示:
当我们执行完文件流操作时, 我们需要切断ifstream的对象“in_stream” 和文件的联系, 我们需要调用成员函数close:
in_stream.close();
用下图形象的表示:
同理, 对于输出文件流:
假设初始状态:
out_stream.close();
上述语句对于输出文件流对象具有相同的效果, 但是还加上了一个额外的效果, 就是文件的最末尾加上了一个“end-of file” mark 以表明文件的结束。
所以, 当我们的程序没有对文件输入任何数据的时候, 切断连接的时候, 效果如下图:
在这种情况下, 文件“Lecture_4”仍然存在, 只不过是空文件(注意文件和文件夹的区别, 文件的后缀名可能是.doc, .txt, .data等等)
Check for Failures with file command
用程序打开或者关闭文件, 常常会出现错误。 例如文件打不开, 或者无法关闭等等。 为了使得我们的程序更更加的robust, 我们就需要检查这些操作是否
成功了。 如果没有成功, 我们需要编写错误处理程序。 一个很简单的检查机制就是使用成员函数“fail()”, 函数调用如下:
in_stream.fail();
调用上述函数返回的是一个Boolean value。 如果没能成功打开, 返回的是True, 如果文件打开成功, 返回的就是false,.。 没能成功打开, 后面的操作就无法执行了, 此时我们可以退出程序, 通过使用“exit(1)” 命令。 exit(1) 命令来自于库cstdlib; 程序如下:
Character Input and OutPut(字符输入和输出)
使用get(..)用于输入字符
假设初始状态为:
当打开一个输入文件(input file时, 我们可以使用成员函数“get(...)" 来extract 或者read文件中 的单个字符。 这个成员函数的参数只有一个, 类型为
“char”的 变量。
语句如下:
in_stream.get(ch);
上述语句具有如下两种效果(参见上原理图):
(1)变量“ch” is assigned the value "4";
(2) ifstream 的对象in_stream 被重新定位(re-positioned)到文件中的下一个输入字符, 也就是“.”。
Output using "put(...)"
初始状态:
我们可以通过ofstream 的对象out_stream的成员函数“put(...)去”input or write single character to a file 。 同样, 这个函数也只有一个类型为“char”
的参数。 具体如下:
out_stream.put('4');
参考如下图:
输入文件流的成员函数“putback(...)”
对于ifstream类而言, 有一个成员函数“putback(....)”。 从表面上肯看, 意思是“put the character back”, 但是事实上, 该函数并没有改变实际的文件。
尽管表现上是这样的(it behaves as if it had)。 例如初始状态为:
执行如下语句后:
in_stream.putback(ch);
得到如下新的状态
Indeed, we can "putback" any character we want to. 语句如下:
in_stream.putback('7');// 将7放到输入流中(7不在输入文件中)
导致如下结果:
检查文件是否读到结尾了
使用“ef()” 检查文件是否结束
Special care has to be taken with input when the end of a file is reached.
许多的C++编译器(包括GNU g++ 和 Microsoft Visual C++) 都incorporate an end-of-file (EOF)的标志(flag)。 if stream 的成员函数“eof()”
可以用于测试这个标志(EOF)被设置成了True 还是 False。
当一个ifstream 的对象与一个文件连接起来的时候。 EOF标志碑设置成了False(即使文件是空的)。 然而, 如果ifstream 的对象“in_stream”的
放置在文件的结尾, 而且EOF flag 是False, 语句:
in_stream.get(ch);
此语句导致变量ch在一个无法预测的状态, 然后设置为EOF标志为True。 一旦EOF标志为True, 然后no attemp should be made to read from the file, since the results
will be unpredicted。
为了形象表示这个过程, 假设我们当前的状态为:
然后执行语句:
in_stream.get(ch);
导致如下结果状态:
再次执行如下数据:
in_stream.get(ch);
最终导致如下状态:
然后执行如下的boolean expression:
in_stream.eof();
此时上述语句的值为True。
运用上面的知识, 下面的一个程序是将文件“Lecture_4”的内容在屏幕上显示出来, 并且将文件copy 到文件“Copy_of_4”:
NOTE: 用C++ 读取.txt, .data(二进制存储的文件)等很容易, 但是读取.doc 文件读出来的是乱码, 不知道问什么。
运行结果如下:
另外, 输入输出文件流也可以作为函数的参数, 程序如下:
输入输出使用运算符号“>>” 和“<<”
到目前为止, 我们只是对单个character进行读入或者读出文件到内存中。 在对底层, ofstream 和 ifstream 只能处理问价内容为sequneces of bytes. 所以当数据类型为“double” 或者“int”的类型, 在写进文件的时候吗必须转换为character才能正确的写进。 另外将文件中的数据读入到内存的时候, 也需要将这些字符转换回去才能够
正确的输出。
但是, 这样的一个过程是繁琐的。 幸运的是, 我们有两个算子“<<” 和 “>>”, 能够自动的实现这些转换。
例如下面, 初始状态为:
执行语句:
out_stream << 437 << ' ';
导致如下状态:
上面的空格很有必要。 因为这两个运算符的操作比较底层, 在我们处理完每一笔数据的时候(each item of data),加上了空格(或者new-line character),
我们的数据才能够正确的在文件中分隔开。
我们使用符号“>>”将文件中的数据读入到内存(数据中)。 例如初始状态为:
其中“n" 表示在程序中已经声明了一个数据类型为int 的变量。 执行下一句:
in_stream >> n;
我们得到如下新的状态:
Notice, 操作运算元 ”>>“跳过了437之前的空格”“。 It always does this, no matter waht datatype it has been reading or expects to read。
参看如下程序。 改程序首先创建一个成为Integers的文件, 该文件涵盖了整数51, 52, 53, 54 and 55。
运行结果为:
不难看出, operator ”>>“会跳过文件中的空格字符, 这里空格字符分开了五个整数。 而函数get(...)
却不会跳过字符。
不应该只是限于keyboard 和screen这两种input 和output devices.。 试想一下, 如果我们的程序需要处理大量的数据的时候, 如果仅仅依靠键盘来手写输入,
那么运行的效率将会是何其的低。 同理, 如果我们仅仅将处理后的大量数据送到屏幕上显示, 二不去保存这些大量的数据, 当我们关掉电脑的时候,
所有的结果数据都想会消失(因为我们的数据在内存中)。这或许就是C++ 文件流处理的motivation。
所以 ,为了应对上面关于输入输出的两个challenges, 我们需要我们的数据存放在一些secondary storage device中, 这些device通常是magnetics
tapes, 或者disc(磁盘中)。 这样在必要的时候, 们就可以通过编写program 创建, 修改, 存取(access)我们的数据。 为了实现这些目的, 我们的数据
以文件(files)的数据结构(data structures)的形式 packageed up on storage devices。
我们可以将文件看成是由一个线性字符序列(a linear sequence of characters)的数据结构组织的。 举一个例子, 下面文件(截图)的存储形式可能看成是是如下形式:
存储方式:
Streams
在我们用C++ 处理文件的之前, 我们已经对流有过了解了。 我们可以将streams 想象成数据从senders 到 receivers 的一个通道(channel)。
就目前而言, 我们将只允许我们的流是单方向的运动。 数据可以从程序输出的输出流(例如程序将处理结果从到显示器显示(output stream), 或者是从到磁盘存储起来
等等)。 亦或是数据从键盘, 或者磁盘中送到程序进行处理的输入流(input stream) .。 NOTE: 输入流还是输出流是站在program的角度看的。
举个例子, 程序开始的时候, 标准输入流'cin'连接到键盘等待用户输入。 输出流'cout' 连接到显示器以便将程序的结果显示在屏幕上。
事实上, 输入流cin 和输出流cout 是stream(流类)objects(对象)。所以这也是OOP的一部分。
在处理文件流的时候, 我们需要一个列举出了关于定义了文件的输入流和输出流的一些operations, 该头文件的名字是“fstream”。 所以我们在编写此类程序之前,
必须在程序之前添加如下的指导语句:
#include <fstream>
Creating Streams
当我们想要在程序中使用文件的输入流和输出流, 第一步就是创建文件流。 ifstream class 用于创建输入流的对象, ofstream 用于创建输出流的对象。
如下:
ifstream in_stream;
ofstream out_stream;
Connecting and Disconnecting Streams to files
创建完了流对象之后, 接下来就是使用openc() 成员函数去把文件与流对象连接起来。 成员函数open() 对于ifstreams对象和ofstream的对象的作用效果
是不同, 也就是说openc() function是porlymorphic的(多态的)。
(1)将ifstream 对象in_stream 与文件“Lecture_4” 连接起来。
in_stream.open("Lecture_4");
可以用下图形象的表示:
将输出文件流ofstream的对象“out_stream” 与文件“Lecture_4”连接起来:
out_stream.open(“Lecture_4”);
注意, 尽管将out_stream 和 “Lecture_4”连
接起来, 但是It also delete the previous contents of the file, ready for new content。 用下图形象的表示:
当我们执行完文件流操作时, 我们需要切断ifstream的对象“in_stream” 和文件的联系, 我们需要调用成员函数close:
in_stream.close();
用下图形象的表示:
同理, 对于输出文件流:
假设初始状态:
out_stream.close();
上述语句对于输出文件流对象具有相同的效果, 但是还加上了一个额外的效果, 就是文件的最末尾加上了一个“end-of file” mark 以表明文件的结束。
所以, 当我们的程序没有对文件输入任何数据的时候, 切断连接的时候, 效果如下图:
在这种情况下, 文件“Lecture_4”仍然存在, 只不过是空文件(注意文件和文件夹的区别, 文件的后缀名可能是.doc, .txt, .data等等)
Check for Failures with file command
用程序打开或者关闭文件, 常常会出现错误。 例如文件打不开, 或者无法关闭等等。 为了使得我们的程序更更加的robust, 我们就需要检查这些操作是否
成功了。 如果没有成功, 我们需要编写错误处理程序。 一个很简单的检查机制就是使用成员函数“fail()”, 函数调用如下:
in_stream.fail();
调用上述函数返回的是一个Boolean value。 如果没能成功打开, 返回的是True, 如果文件打开成功, 返回的就是false,.。 没能成功打开, 后面的操作就无法执行了, 此时我们可以退出程序, 通过使用“exit(1)” 命令。 exit(1) 命令来自于库cstdlib; 程序如下:
#include <iostream> #include <fstream> #include <cstdlib> using namespace std; int main() { ifstream in_stream; in_stream.open("Lecture_4"); if (in_stream.fail()) { cout << "Sorry, the file couldn't be opened!\n"; exit(1); } ...
Character Input and OutPut(字符输入和输出)
使用get(..)用于输入字符
假设初始状态为:
当打开一个输入文件(input file时, 我们可以使用成员函数“get(...)" 来extract 或者read文件中 的单个字符。 这个成员函数的参数只有一个, 类型为
“char”的 变量。
语句如下:
in_stream.get(ch);
上述语句具有如下两种效果(参见上原理图):
(1)变量“ch” is assigned the value "4";
(2) ifstream 的对象in_stream 被重新定位(re-positioned)到文件中的下一个输入字符, 也就是“.”。
Output using "put(...)"
初始状态:
我们可以通过ofstream 的对象out_stream的成员函数“put(...)去”input or write single character to a file 。 同样, 这个函数也只有一个类型为“char”
的参数。 具体如下:
out_stream.put('4');
参考如下图:
输入文件流的成员函数“putback(...)”
对于ifstream类而言, 有一个成员函数“putback(....)”。 从表面上肯看, 意思是“put the character back”, 但是事实上, 该函数并没有改变实际的文件。
尽管表现上是这样的(it behaves as if it had)。 例如初始状态为:
执行如下语句后:
in_stream.putback(ch);
得到如下新的状态
Indeed, we can "putback" any character we want to. 语句如下:
in_stream.putback('7');// 将7放到输入流中(7不在输入文件中)
导致如下结果:
Checking for the End of an Input File
检查文件是否读到结尾了使用“ef()” 检查文件是否结束
Special care has to be taken with input when the end of a file is reached.
许多的C++编译器(包括GNU g++ 和 Microsoft Visual C++) 都incorporate an end-of-file (EOF)的标志(flag)。 if stream 的成员函数“eof()”
可以用于测试这个标志(EOF)被设置成了True 还是 False。
当一个ifstream 的对象与一个文件连接起来的时候。 EOF标志碑设置成了False(即使文件是空的)。 然而, 如果ifstream 的对象“in_stream”的
放置在文件的结尾, 而且EOF flag 是False, 语句:
in_stream.get(ch);
此语句导致变量ch在一个无法预测的状态, 然后设置为EOF标志为True。 一旦EOF标志为True, 然后no attemp should be made to read from the file, since the results
will be unpredicted。
为了形象表示这个过程, 假设我们当前的状态为:
然后执行语句:
in_stream.get(ch);
导致如下结果状态:
再次执行如下数据:
in_stream.get(ch);
最终导致如下状态:
然后执行如下的boolean expression:
in_stream.eof();
此时上述语句的值为True。
运用上面的知识, 下面的一个程序是将文件“Lecture_4”的内容在屏幕上显示出来, 并且将文件copy 到文件“Copy_of_4”:
NOTE: 用C++ 读取.txt, .data(二进制存储的文件)等很容易, 但是读取.doc 文件读出来的是乱码, 不知道问什么。
#include <iostream> #include <fstream> using namespace std; int main() { char character; ifstream in_stream; ofstream out_stream; in_stream.open("D:\\demoFileStream.txt"); out_stream.open("D:\\Copy_of_demoFileStream.txt"); in_stream.get(character); while(!in_stream.eof()) { cout << character; out_stream.put(character); in_stream.get(character); } out_stream.close(); in_stream.close(); return 0; }
运行结果如下:
另外, 输入输出文件流也可以作为函数的参数, 程序如下:
#include <iostream> #include <fstream> using namespace std; void copy_to(ifstream& in, ofstream& out); /* MAIN PROGRAM: */ int main() { ifstream in_stream; ofstream out_stream; in_stream.open("Lecture_4"); out_stream.open("Copy_of_4"); copy_to(in_stream, out_stream); out_stream.close(); in_stream.close(); return 0; } /* END OF MAIN PROGRAM */ /* FUNCTION TO COPY A FILE TO ANOTHER FILE AND TO THE SCREEN: */ void copy_to(ifstream& in, ofstream& out) { char character; in.get(character); while (!in.eof()) { cout << character; out.put(character); in.get(character); } } /* END OF FUNCTION */
输入输出使用运算符号“>>” 和“<<”
到目前为止, 我们只是对单个character进行读入或者读出文件到内存中。 在对底层, ofstream 和 ifstream 只能处理问价内容为sequneces of bytes. 所以当数据类型为“double” 或者“int”的类型, 在写进文件的时候吗必须转换为character才能正确的写进。 另外将文件中的数据读入到内存的时候, 也需要将这些字符转换回去才能够
正确的输出。
但是, 这样的一个过程是繁琐的。 幸运的是, 我们有两个算子“<<” 和 “>>”, 能够自动的实现这些转换。
例如下面, 初始状态为:
执行语句:
out_stream << 437 << ' ';
导致如下状态:
上面的空格很有必要。 因为这两个运算符的操作比较底层, 在我们处理完每一笔数据的时候(each item of data),加上了空格(或者new-line character),
我们的数据才能够正确的在文件中分隔开。
我们使用符号“>>”将文件中的数据读入到内存(数据中)。 例如初始状态为:
其中“n" 表示在程序中已经声明了一个数据类型为int 的变量。 执行下一句:
in_stream >> n;
我们得到如下新的状态:
Notice, 操作运算元 ”>>“跳过了437之前的空格”“。 It always does this, no matter waht datatype it has been reading or expects to read。
参看如下程序。 改程序首先创建一个成为Integers的文件, 该文件涵盖了整数51, 52, 53, 54 and 55。
#include <iostream> #include <fstream> using namespace std; int main() { char character; int number = 51; int count = 0; ofstream out_stream; ifstream in_stream1; /* Stream for counting integers. */ ifstream in_stream2; /* Stream for counting characters. */ /* Create the file */ out_stream.open("D:\\Integers.txt"); for (count = 1 ; count <= 5 ; count++) out_stream << number++ << ' '; out_stream.close(); //关闭 /* Count the integers in the file */ in_stream1.open("D:\\Integers.txt"); count = 0; in_stream1 >> number; while (!in_stream1.eof()) { count++; in_stream1 >> number; } in_stream1.close(); cout << "There are " << count << " integers in the file,\n"; /* Count the non-blank characters */ in_stream2.open("D:\\Integers.txt"); count = 0; in_stream2 >> character; while (!in_stream2.eof()) { count++; in_stream2 >> character; } in_stream2.close(); cout << "represented using " << count << " characters.\n"; return 0; }
运行结果为:
不难看出, operator ”>>“会跳过文件中的空格字符, 这里空格字符分开了五个整数。 而函数get(...)
却不会跳过字符。
相关文章推荐
- Linux - 操作文件与目录(manipulating files and directories)
- JHTP自测题_第十五章_文件、流和对象序列化(Files, Streams, and Object Serialization)
- UNIX高级环境编程(5)Files And Directories - 文件相关时间,目录文件相关操作
- 学习实战完全笔记--JavaSE----流与文件(Streams and Files)
- 文件和流(Files and Streams)之 DirectoryInfo类和FileInfo
- JHTP小结_第十五章_文件、流和对象序列化(Files, Streams, and Object Serialization)
- UNIX高级环境编程(5)Files And Directories - 文件相关时间,目录文件相关操作
- 文件和流(Files and Streams)之 Directory类和File类
- Linux - 操作文件与目录(manipulating files and directories)
- 基于C,C++的文件操作 20051027
- C++基本文件操作
- C++ 文件操作
- C++ 文件操作
- c++文件常见操作示例
- torque游戏引擎DTS文件的LOD实现(含reflection反射材质演示)-The LOD and reflection in DTS files
- 用c++ 操作mysql 数据库类(for linux or windows and others)
- C++中关于文件操作的函数
- Outlook 2007: Accounts and data files 帐户和数据文件 - RSS Feeds
- C++中基本的文件操作
- 用c++ 操作mysql 数据库类(for linux or windows and others)