如何使用 <fstream> 類(lèi)進(jìn)行文件的 I/O 處理
作者:Danny Kalev
編譯:MTT 工作室
下載源代碼
原文出處:How to Use <fstream> Classes for File I/O
摘要:傳統(tǒng)的文件 I/O 庫(kù)如 Unix 的 <io.h> 和 <stdio.h> ,由于其程序接口的原因,在很大程度上強(qiáng)制程序員進(jìn)行某些處理,缺乏類(lèi)型安全和國(guó)際化支持。C++ 的 <fstream> 庫(kù)則在文件的 I/O 方面提供了一個(gè)增強(qiáng)的、面向?qū)ο蟮摹⒕哂袊?guó)際化意識(shí)的庫(kù)。本文將介紹如何使用這個(gè)庫(kù)進(jìn)行文件的 I/O 處理并利用它來(lái)編寫(xiě)易于跨平臺(tái)的代碼。 |
大多數(shù) C++ 程序員都熟悉不止一個(gè)文件 I/O 庫(kù)。首先是傳統(tǒng)的 Unix 風(fēng)格的庫(kù),它由一些低級(jí)函數(shù)如 read() 和 open()組成。其次是 ANSI C 的 <stdio.h> 庫(kù),它包含 fopen() 和 fread()等函數(shù)。其它的還有一些具備所有權(quán)的庫(kù)或框架,比如 MFC,它有很多自己的文件處理類(lèi)。
這些庫(kù)一般都很難跨平臺(tái)使用。更糟的是,上述提到的 C 庫(kù)由于其程序接口的原因,在很大程度上強(qiáng)制程序員進(jìn)行某些處理,而且缺乏類(lèi)型安全支持。
標(biāo)準(zhǔn) C++ 提供提供了一個(gè)增強(qiáng)的、面向?qū)ο蟮摹⒕哂袊?guó)際化意識(shí)的 <fstream> 庫(kù)。這個(gè)庫(kù)包含一系列派生于標(biāo)準(zhǔn) ios_base 和 ios 類(lèi)的類(lèi)模板。因此, <fstream> 提供了高級(jí)的自動(dòng)控制機(jī)制和健壯性。本文下面將示范如何使用 <fstream> 類(lèi)實(shí)現(xiàn)文件的輸入/輸出處理:
第一步:創(chuàng)建文件流
輸入文件流(ifstream)支持重載的 >> 操作符,同樣,輸出文件流(ofstream)支持重載的 << 操作符。結(jié)合了輸入和輸出的文件流被稱(chēng)為 fstream。下面的程序創(chuàng)建了一個(gè) ifstream 對(duì)象:dict,并將該對(duì)象中的每一個(gè)單字顯示到屏幕上:
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main()
{
string s;
cout<<"enter dictionary file: ";
cin>>s;
ifstream dict (s.c_str());
if (!dictionary) // were there any errors on opening?
exit(-1);
while (dictionary >> s) cout << s <<''\n'';
}
我們必須調(diào)用 string::c_str() 成員函數(shù),因?yàn)?fstream 對(duì)象只接受常量字符串作為文件名。當(dāng)你將文件名作為參數(shù)傳遞時(shí),構(gòu)造函數(shù)試圖打開(kāi)指定的文件。接著,我們用重載的 !操作符來(lái)檢查文件的狀態(tài)。如果出錯(cuò),該操作符估值為 true。最后一行是個(gè)循環(huán),每次反復(fù)都從文件讀取一個(gè)單字,將它拷貝到 s,然后顯示出來(lái)。注意我們不必顯式地檢查 EOF,因?yàn)橹剌d操作符 >> 會(huì)自動(dòng)處理。此外,我們不用顯式地關(guān)閉此文件,因?yàn)槲鰳?gòu)函數(shù)會(huì)為我們做這件事情。
過(guò)時(shí)和荒廢的 <fstream.h> 庫(kù)支持 ios::nocreate 和 ios::noreplace 標(biāo)志。但新的 <fstream> 庫(kù)已經(jīng)取代了 <fstream.h> 并不再支持這兩個(gè)標(biāo)志。
文件的打開(kāi)模式
如果你不顯式指定打開(kāi)模式,fstream 類(lèi)將使用默認(rèn)值。例如,ifstream 默認(rèn)以讀方式打開(kāi)某個(gè)文件并將文件指針置為文件的開(kāi)始處。為了向某個(gè)文件寫(xiě)入數(shù)據(jù),你需要?jiǎng)?chuàng)建一個(gè) ofstream 對(duì)象。<fstream> 定義了下列打開(kāi)模式和文件屬性:
ios::app // 從后面添加
ios::ate // 打開(kāi)并找到文件尾
ios::binary // 二進(jìn)制模式 I/O (與文本模式相對(duì))
ios::in // 只讀打開(kāi)
ios::out // 寫(xiě)打開(kāi)
ios::trunc // 將文件截為 0 長(zhǎng)度
你可以用位域操作符 OR 組合這些標(biāo)志:
ofstream logfile("login.dat", ios::binary | ios::app);
fstream 類(lèi)型對(duì)象同時(shí)支持讀和寫(xiě)操作:
fstream logfile("database.dat", ios::in | ios::out);
第二步:設(shè)置文件的位置
文件具備一個(gè)邏輯指針,它指向該文件中的某個(gè)偏移位置。你可以通過(guò)調(diào)用seekp()成員函數(shù),以字節(jié)為單位將這個(gè)指針定位到文件的任意位置。為了獲取從文件開(kāi)始處到當(dāng)前偏移的字節(jié)數(shù),調(diào)用seekp()即可。在下面的例子中,程序?qū)⑽募恢们耙?0個(gè)字節(jié),然后調(diào)用 tellp()報(bào)告新位置:
ofstream fout("parts.txt");
fout.seekp(10); // 從0偏移開(kāi)始前進(jìn) 10 個(gè)字節(jié)
cout<<"new position: "<<fout.tellp(); // 顯示 10
你可以用下面的常量重新定位文ian指針:
ios::beg // 文件開(kāi)始位置
ios::cur // 當(dāng)前位置,例如: ios::cur+5
ios::end // 文件尾
第三步:讀寫(xiě)數(shù)據(jù)
fstream 類(lèi)為所有內(nèi)建數(shù)據(jù)類(lèi)型以及 std::string 和 std::complex 類(lèi)型重載 << 和 >> 操作符。下面的例子示范了這些操作符的使用方法:
fstream logfile("log.dat");
logfile<<time(0)<<"danny"<<''\n''; // 寫(xiě)一條新記錄
logfile.seekp(ios::beg); // 位置重置
logfile>>login>>user; // 讀取以前寫(xiě)入的值
作者簡(jiǎn)介
Danny Kalev 是一名通過(guò)認(rèn)證的系統(tǒng)分析師和軟件工程師,專(zhuān)攻 C++ 和形式語(yǔ)言理論。1997 年到 2000 年期間,他是 C++ 標(biāo)準(zhǔn)委員會(huì)成員。最近他以?xún)?yōu)異成績(jī)完成了他在普通語(yǔ)言學(xué)研究方面的碩士論文。 業(yè)余時(shí)間他喜歡聽(tīng)古典音樂(lè),閱讀維多利亞時(shí)期的文學(xué)作品,研究 Hittite、Basque 和 Irish Gaelic 這樣的自然語(yǔ)言。其它興趣包括考古和地理。Danny 時(shí)常到一些 C++ 論壇并定期為不同的 C++ 網(wǎng)站和雜志撰寫(xiě)文章。他還在教育機(jī)構(gòu)講授程序設(shè)計(jì)語(yǔ)言和應(yīng)用語(yǔ)言課程。
Visual C++ Error Messages
This page contains a listing of "difficult to diagnose" error messages and possible fixes. I haven't taught a programming class that uses Visual C++ in several years so this list is probably out of date by now. It was valid for Microsoft Visual C++ version 6.0 service pack 3.
C1001: INTERNAL COMPILER ERROR (compiler file 'msc1.cpp', line 1786) Please choose the Technical Support command on the Visual C++ Help menu, or open the Technical Support help file for more information
This error results from leaving off the parentheses immediately following the function name in a function header. To correct the error simply add () to the end of the function name.
C1010: unexpected end of file while looking for precompiled header directive
If your project is an MFC AppWizard created project then this error results from not #including StdAfx.h as the first #include statement (before any other #includes, data declarations, or executable program code).
C1083: Cannot open precompiled header file: 'Debug/<Project-Name>.pch': No such file or directory
This error results from a missing file - the compiled version of StdAfx.cpp. Visual C++ does a poor job of keeping track of this file and frequently "forgets" how to build it. This problem often occurs after restoring a saved workspace from diskette without the Debug directory. To fix the error select StdAfx.cpp from the workspace file list them choose Compile from the Build menu. If that doesn't work the go to Project -> Settings, select the C/C++ tab, and click the radio button labeled Create Precompiled Headers.
C2001: newline in constant
This error is usually caused by a string or character constant that is missing its closing ' or " symbol.
C2065: '<data-member name>' : undeclared identifier
If this error occurs in one of your member functions then it is generally the result of forgetting the class scope operator in front of the function name in your .cpp file.
C2143: syntax error : missing ';' before 'PCH creation point'
Check each of the #include files to ensure that the closing brace of each class declaration is followed by a semicolon.
C2143: syntax error : missing ';' before '*'
If this error is followed by two C2501 errors then the problem is an undeclared class name within a pointer declaration.
For example, the declaration:
CClass *pObject;
will generate the above error message followed by a C2501 error message for 'CClass' and another C2501 message for 'pObject'. The problem is that the compiler isn't recognizing CClass as a valid class/type name. To correct the problem add a #i nclude of the file containing the declaration of CClass (e.g., #i nclude CClass.h)
C2447: missing function header (old-style formal list?)
This error usually results from a missing { or use of a ; instead of a { following the parameter list of a function header.
C2511: '<function-name>' : overloaded member function not found in '<class-name>'
This error results from a mismatch in the parameter list of a member function declaration (.h file) and definition (.ccp file). Check the forward declaration of the function in the .h file and its definition in the .cpp file and ensure that the number of parameters and the type of each parameter match exactly.
C2512: '<constructor-function-name>' : no appropriate default constructor available
This error usually occurs when you implement the constructor function of a derived class and forget to include parameter passing to the base class constructor function. For example assume that CDerived is derived from CBase and that the CBase constructor function requires one parameter (e.g., int A). If you define the CDerived constructor function as:
CDerived::CDerived(int A, int B) { ... }
the compiler will issue the above error message on the line containing the function header of CDerived::CDerived() because you haven't provided instructions for routing the parameter A to CBase::CBase(). Because you didn't provide instructions the compiler assumes that CBase::CBase() requires no arguments and it complains because no version of CBase::CBase() has been defined that accepts zero arguments.
If you intended to provide a version of CBase::CBase() that requires no arguments then the error message indicates that you forgot to declare that function in your base class declaration (e.g., in CBase.h).
If CBase::CBase() does require one or more arguments then you must correct the problem by including explicit instructions for passing parameters from the derived class constructor function to the base class constructor function. The correction for the example above is:
CDerived::CDerived(int A, int B) : CBase(A) { ... }
C2556: '<function-name>' : overloaded functions only differ by return type
C2371: '<function-name>' : redefinition; different basic types
These errors usually result from a mismatch of function type between a .h and .cpp file. Check the forward declaration of the function in the .h file and its definition in the .cpp file and make the function return type identical in both files.
C2601: '<function-name>' : local function definitions are illegal
This error results from defining one function inside the body of another function. It usually means that you omitted one or more } symbols in the function just before the function named in the error message.
C2653: '<Class-Name>' : is not a class or namespace name
This error usually results from not having #include "StdAfx.h" as the first #include statement in your class.cpp file. It can also occur if your class definition is in a .h file and you forget to #include that .h file in another file that refers to the class name.
C2661: '<Class-Name>::<Function-Name>' : no overloaded function takes n parameters
This error indicates a mismatch between the parameters used in a function call (e.g., from main.cpp) and the declaration of the function. The function call is passing n parameters and there is no function declaration that uses that number of parameters.
LNK1104: Cannot open file nafxcwd.lib
This error sometimes occurs when a project uses a class from the MFC but the project settings don't explicitly tell the link editor to look in the MFC libraries.
Go to Project --> Settings (Build --> Settings in Visual C++ 4.0). On the General tab check the box that says "Use MFC in a Shared DLL".
LNK1168: cannot open Debug\<Project-Name>.exe for writing
This error occurs when the link editor attempts to write to a .exe file that is currently in use. The .exe file of an executing program is write protected until the program is terminated. Look at the status bar at the bottom of your screen and find the icon representing your executable application. Open the application and exit from it. Then select Build.
LNK2001: unresolved external symbol __endthreadex
LNK2001: unresolved external symbol __beginthreadex
These errors result from using an MFC object or function without telling the link editor to search the MFC libraries.
Go to Project --> Settings (Build --> Settings in Visual C++ 4.0). On the General tab check the box that says "Use MFC in a Shared DLL".
LNK2001: unresolved external symbol _main
Your project doesn't contain a function called main(). The error usually results from forgeting to add main.cpp to the project workspace.
<File>.obj : error LNK2001: unresolved external symbol "public: void __thiscall <Class1>::<Function1>(<Type>)"
This a generic form of a LNK2001 error where <File>.obj can be any object file in your project and <Class1>::<Function1>(<Type>) can be any function in any class. Substitute the specific <File>, <Class>, <Function>, and <Type> in your message into the instructions below to diagnose and correct the problem.
An LNK2001 error means that the link editor is looking for a compiled function and can't find it. The call to the "missing function" is somewhere in <File>.cpp. Unfortunately, double-clicking on the error message won't take you to the point in <File.cpp> where the function is called but you can search for it with Find or Find In Files. The function the link editor can't find is a member of <Class>, its name is <Function1>, and its return type is <Type>.
There are two common reasons for a LNK2001 error:
1. The call in <File>.cpp doesn't match the function prototype in <Class>.h and/or the implementation in <Class>.cpp. The mismatch may be in the function name, return type, or number and/or type of parameters. Correction strategies include:
o Check that the function name is spelled the same (case sensitive) in all three files (File.cpp, Class.h, and Class.cpp).
o Check that the function is actually declared and defined within <Class> - perhaps you defined it as a member of a different class or perhaps you tried to call the function (in <File>.cpp) using an object or object pointer of a different class.
o Check that the number and type of parameters in the function implementation (in <Class>.cpp) matches the number and type of parameters declared in the function declaration in <Class>.h.
o Check that the number and type of parameters in the function call (in <File>.cpp) matches the number and type of parameters declared in the function header in <Class>.cpp.
2. The function was never declared or was declared but never defined. To see if either is the case go to the ClassView window of the Workspace view. Click the + next to <Class> and find <Function> in the list of member functions.
o If <Function> is NOT in the list then it was never declared or defined - add a declaration to the class declaraion in <Class>.h and implement the function in <Class>.cpp.
If <Function> is in the list then right click on it and select Go To Definition from the pop-up menu. If you get the error message Cannot find definition (implementation) of this function then the function was declared but never defined (implemented). Implement the function to
o <Class>.cpp.
LNK2005: <some-long-string-of-mostly-garbage> already defined in <name>.lib(<name>.obj)
This error usually results from including a source code file multiple times. If you recognize any of the names in the message then it probably results from multiple inclusion of one of your own header files. Check to be sure that you've used #ifndef/#define/#endif properly your header files. If you don't recognize the name then it's probably multiple inclusion of a system file (e.g., afxwin.h). Make sure that you haven't explicitly included something in main.cpp that is already included in one of your own header files. Also check that you haven't #included a .cpp file where you should have #included a .h file