文件输入输出(Input/Output with files)
2006-07-18 19:04
393 查看
Input/Output with files |
|
ofstream: 文件输出的Stream类
ifstream: 文件输入的Stream 类
fstream: 文件输入输出的Stream类
这几个类是直接或者间接从istream和 ostream类派生的。我们已经使用过这两种类型的一些对象:cin是istream的一个对象,而cout是ostream的对象。所以,我们已经有了使用和文件流(file streams)相关的类的经验。实际上,我们能够像使用我们已经习惯了的cin和cout的同样的方式使用文件流,唯一的区别是,我们必须把文件流和物理文件关联起来。看看下面的例子:
// basic file operations #include <iostream> #include <fstream> using namespace std; int main () { ofstream myfile; myfile.open ("example.txt"); myfile << "Writing this to a file./n"; myfile.close(); return 0; } | [file example.txt] Writing this to a file |
我们一步一步来:
打开一个文件
通常来说,这些stream类的对象的头一个操作就是和一个真实文件相关联。这个操作被称为打开文件。在程序中一个stream对象(指某个stream类的一个实例,前面例子中的stream对象就是myfile)表征一个打开的文件,任何对这个stream对象的输入输出操作都会反应到与之相关联的物理文件上。
为了打开一个文件,我们使用stream对象的open()成员函数:
open (filename, mode);
其中filename是一个以null结尾的const char *型字符串(和string相同的类型),指明要被打开的文件名;是选项参数,mode可以是下表里标志的组合:
ios::in | Open for input operations. |
ios::out | Open for output operations. |
ios::binary | Open in binary mode. |
ios::ate | Set the initial position at the end of the file. If this flag is not set to any value, the initial position is the beginning of the file. |
ios::app | All output operations are performed at the end of the file, appending the content to the current content of the file. This flag can only be used in streams open for output-only operations. |
ios::trunc | If the file opened for output operations already existed before, its previous content is deleted and replaced by the new one. |
ofstream myfile; myfile.open ("example.bin", ios::out | ios::app | ios::binary); |
class | default mode parameter |
ofstream | ios::out |
ifstream | ios::in |
fstream | ios::in | ios::out |
默认值仅仅是在函数调用时缺省mode参数的情况下才会生效。如果函数调用时指定了mode参数,默认参数会被覆盖,而不是于指定的参数组合。
以二进制方式打开的文件流的输入输出过程和文件的格式无关。文本文件可以用非二进制方式打开,这样在格式化字符的时候,会有一些转义的操作发生(比如换行和回车)。
因为操作文件流的第一项任务通常就是打开一个文件,所以这三个类都提供了自动调用open()函数的构造函数,使用与open()完全一样的参数。所以,我们也可以用下面的代码来声明一个和前面例子一样的myfile对象并且包含了打开文件的操作:
ofstream myfile ("example.bin", ios::out | ios::app | ios::binary); |
为了检查一个文件流是否成功地打开了一个文件,可以不带参数地调用is_open()函数来进行判断。这个成员函数返回一个bool型值,返回true表示打开成功,返回false表示打开失败:
if (myfile.is_open()) { /* ok, proceed with output */ } |
当输入输出操作结束以后,我们应该关闭(close)这个文件以便使其资源重新可用。关闭文件使用close()成员函数。这个函数不需要参数,它所做的事就是置空相关联的缓冲区并且关闭打开的文件:
myfile.close(); |
如果一个stream对象在析构的时候仍然打开着一个文件,析构函数将自动调用close()成员函数来关闭文件。
文本文件
我们不包含ios::binary标志打开文件的时候将创建文本文件流。文本文件设计为储存文本,所以在输入活着输出的时候会遇到格式转换(formatting transformations),而并不是保持它们二进制语义。
文本文件上的数据输出操作和使用cout的操作是一样的:
// writing on a text file #include <iostream> #include <fstream> using namespace std; int main () { ofstream myfile ("example.txt"); if (myfile.is_open()) { myfile << "This is a line./n"; myfile << "This is another line./n"; myfile.close(); } else cout << "Unable to open file"; return 0; } | [file example.txt] This is a line. This is another line. |
// reading a text file #include <iostream> #include <fstream> #include <string> using namespace std; int main () { string line; ifstream myfile ("example.txt"); if (myfile.is_open()) { while (! myfile.eof() ) { getline (myfile,line); cout << line << endl; } myfile.close(); } else cout << "Unable to open file"; return 0; } | This is a line. This is another line. |
检测状态标志
除了eof()用以检测是否到达文件末尾以外,还有一些成员函数可以用来检测一个流对象的其他状态(都以bool型作为返回值):
bad()
Returns true if a reading or writing operation fails. For example in the case that we try to write to a file that is not open for writing or if the device where we try to write has no space left.
fail()
Returns true in the same cases as bad(), but also in the case that a format error happens, like when an alphabetical character is extracted when we are trying to read an integer number.
eof()
Returns true if a file open for reading has reached the end.
good()
It is the most generic state flag: it returns false in the same cases in which calling any of the previous functions would return true.
为了重置调用上述这些成员函数后所设定的状态标志,我们应该调用clear()函数,调用它不需要带参数。
get和put流指针
所有的输入/输出流对象都至少拥有一个内部的流指针:
Ifstream和istream类似,有一个被称作get pointer的指针指向下一个输入操作将要读入的元素。
Ofstream和ostream类似,有一个被称作put pointer的指针指向下一个输出操作将要写入的位置。
最后, fstream从iostream(它是从istream和ostream派生而来)继承了get pointer和put pointer两者。
通过下列的成员函数来操作这些指向读入或者写入位置的内部流指针:
tellg()和tellp()
这两个函数没有参数,返回一个成员类型pos_type的值,pos_type是一个整数类型,代表当前get stream pointer的位置(如果是tellg)或put stream pointer的位置(如果是tellp)。
seekg()和seekp()
这两个函数允许我们改变get和put流指针的位置。它们都有两个不同的原型,第一个原型是:
seekg ( position );
seekp ( position );
使用这一对原型,流指针将会被设置为position指定的绝对位置(从文件起始开始的位置)。参数的类型和tellg与tellp的返回值一样:成员类型pos_type,一个整型的值。
第二种原型是:
seekg ( offset, direction );
seekp ( offset, direction );
使用这一对原型,Using this prototype, the position of the get or put pointer is set to an offset value relative to some specific point determined by the parameter direction. offset is of the member type off_type, which is also an integer type. And direction is of type seekdir, which is an enumerated type (enum) that determines the point from where offset is counted from, and that can take any of the following values:
ios::beg | offset counted from the beginning of the stream |
ios::cur | offset counted from the current position of the stream pointer |
ios::end | offset counted from the end of the stream |
// obtaining file size #include <iostream> #include <fstream> using namespace std; int main () { long begin,end; ifstream myfile ("example.txt"); begin = myfile.tellg(); myfile.seekg (0, ios::end); end = myfile.tellg(); myfile.close(); cout << "size is: " << (end-begin) << " bytes./n"; return 0; } | size is: 40 bytes. |
In binary files, to input and output data with the extraction and insertion operators (<< and >>) and functions like getline is not efficient, since we do not need to format any data, and data may not use the separation codes used by text files to separate elements (like space, newline, etc...).
File streams include two member functions specifically designed to input and output binary data sequentially: write and read. The first one (write) is a member function of ostream inherited by ofstream. And read is a member function of istream that is inherited by ifstream. Objects of class fstream have both members. Their prototypes are:
write ( memory_block, size );
read ( memory_block, size );
Where memory_block is of type "pointer to char" (char*), and represents the address of an array of bytes where the read data elements are stored or from where the data elements to be written are taken. The size parameter is an integer value that specifies the number of characters to be read or written from/to the memory block.
// reading a complete binary file #include <iostream> #include <fstream> using namespace std; ifstream::pos_type size; char * memblock; int main () { ifstream file ("example.txt", ios::in|ios::binary|ios::ate); if (file.is_open()) { size = file.tellg(); memblock = new char [size]; file.seekg (0, ios::beg); file.read (memblock, size); file.close(); cout << "the complete file content is in memory"; delete[] memblock; } else cout << "Unable to open file"; return 0; } | the complete file content is in memory |
First, the file is open with the ios::ate flag, which means that the get pointer will be positioned at the end of the file. This way, when we call to member tellg(), we will directly obtain the size of the file. Notice the type we have used to declare variable size:
ifstream::pos_type size; |
int size; size = (int) file.tellg(); |
memblock = new char[size]; |
file.seekg (0, ios::beg); file.read (memblock, size); file.close(); |
Buffers and Synchronization
When we operate with file streams, these are associated to an internal buffer of type streambuf. This buffer is a memory block that acts as an intermediary between the stream and the physical file. For example, with an ofstream, each time the member function put (which writes a single character) is called, the character is not written directly to the physical file with which the stream is associated. Instead of that, the character is inserted in that stream's intermediate buffer.
When the buffer is flushed, all the data contained in it is written to the physical medium (if it is an output stream) or simply freed (if it is an input stream). This process is called synchronization and takes place under any of the following circumstances:
When the file is closed: before closing a file all buffers that have not yet been flushed are synchronized and all pending data is written or read to the physical medium.
When the buffer is full: Buffers have a certain size. When the buffer is full it is automatically synchronized.
Explicitly, with manipulators: When certain manipulators are used on streams, an explicit synchronization takes place. These manipulators are: flush and endl.
Explicitly, with member function sync(): Calling stream's member function sync(), which takes no parameters, causes an immediate synchronization. This function returns an int value equal to -1 if the stream has no associated buffer or in case of failure. Otherwise (if the stream buffer was successfully synchronized) it returns 0.
相关文章推荐
- C++ 标准函数库 —— 文件的输入输出 (Input/Output with files)
- C++ 标准函数库 —— 文件的输入输出 (Input/Output with files)
- Ubuntu 16.04使用NASM编译时用ld链接程序出现:i386 架构于输入文件 sandbox.o 与 i386:x86-64 输出不兼容(I386 architecture in the input file sandbox.o is not compatible with i386: x86-64 output)
- Input/Output with files
- 输入输出函数 Input/Output with files
- c++教程(二十五:Input/output with files)
- Input/Output with files
- OpenCV--File Input and Output using XML and YAML files
- android应用私有存储文件的写入与读取-openFileInput 和 openFileOutput
- Qt模块化笔记之core——Input/Output文件操作-流QTextStream使用
- C++——流的文件I/O(Input & Output)
- Android数据存储之文件 openFileOutput & openFileInput
- android文件的写入与读取---简单的文本读写context.openFileInput() context.openFileOutput()
- Qt模块化笔记之core——Input/Output文件操作(2)
- usr/bin/ld: i386 architecture of input file XXX.a( xxx.o) is incompatible with i386:x86-64 output
- logstash启动报配置文件错误Expected one of #, input, filter, output at line 1, column 1 (byte 1) after
- File Input and Output with R
- The installer encountered an error copying files to the hard disk: [Errno 5] Input/output error
- openFileInput()和 openFileOutput()方法利用java流将数据存储到文件中
- Qt模块化笔记之core——Input/Output文件操作-流QDataStream使用