如何使用 <fstream> 類進行文件的 I/O 處理
作者:Danny Kalev
編譯:MTT 工作室
下載源代碼
原文出處:How to Use <fstream> Classes for File I/O
摘要:傳統的文件 I/O 庫如 Unix 的 <io.h> 和 <stdio.h> ,由于其程序接口的原因,在很大程度上強制程序員進行某些處理,缺乏類型安全和國際化支持。C++ 的 <fstream> 庫則在文件的 I/O 方面提供了一個增強的、面向對象的、具有國際化意識的庫。本文將介紹如何使用這個庫進行文件的 I/O 處理并利用它來編寫易于跨平臺的代碼。 |
大多數 C++ 程序員都熟悉不止一個文件 I/O 庫。首先是傳統的 Unix 風格的庫,它由一些低級函數如 read() 和 open()組成。其次是 ANSI C 的 <stdio.h> 庫,它包含 fopen() 和 fread()等函數。其它的還有一些具備所有權的庫或框架,比如 MFC,它有很多自己的文件處理類。
這些庫一般都很難跨平臺使用。更糟的是,上述提到的 C 庫由于其程序接口的原因,在很大程度上強制程序員進行某些處理,而且缺乏類型安全支持。
標準 C++ 提供提供了一個增強的、面向對象的、具有國際化意識的 <fstream> 庫。這個庫包含一系列派生于標準 ios_base 和 ios 類的類模板。因此, <fstream> 提供了高級的自動控制機制和健壯性。本文下面將示范如何使用 <fstream> 類實現文件的輸入/輸出處理:
第一步:創建文件流
輸入文件流(ifstream)支持重載的 >> 操作符,同樣,輸出文件流(ofstream)支持重載的 << 操作符。結合了輸入和輸出的文件流被稱為 fstream。下面的程序創建了一個 ifstream 對象:dict,并將該對象中的每一個單字顯示到屏幕上:
#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'';
}
我們必須調用 string::c_str() 成員函數,因為 fstream 對象只接受常量字符串作為文件名。當你將文件名作為參數傳遞時,構造函數試圖打開指定的文件。接著,我們用重載的 !操作符來檢查文件的狀態。如果出錯,該操作符估值為 true。最后一行是個循環,每次反復都從文件讀取一個單字,將它拷貝到 s,然后顯示出來。注意我們不必顯式地檢查 EOF,因為重載操作符 >> 會自動處理。此外,我們不用顯式地關閉此文件,因為析構函數會為我們做這件事情。
過時和荒廢的 <fstream.h> 庫支持 ios::nocreate 和 ios::noreplace 標志。但新的 <fstream> 庫已經取代了 <fstream.h> 并不再支持這兩個標志。
文件的打開模式
如果你不顯式指定打開模式,fstream 類將使用默認值。例如,ifstream 默認以讀方式打開某個文件并將文件指針置為文件的開始處。為了向某個文件寫入數據,你需要創建一個 ofstream 對象。<fstream> 定義了下列打開模式和文件屬性:
ios::app // 從后面添加
ios::ate // 打開并找到文件尾
ios::binary // 二進制模式 I/O (與文本模式相對)
ios::in // 只讀打開
ios::out // 寫打開
ios::trunc // 將文件截為 0 長度
你可以用位域操作符 OR 組合這些標志:
ofstream logfile("login.dat", ios::binary | ios::app);
fstream 類型對象同時支持讀和寫操作:
fstream logfile("database.dat", ios::in | ios::out);
第二步:設置文件的位置
文件具備一個邏輯指針,它指向該文件中的某個偏移位置。你可以通過調用seekp()成員函數,以字節為單位將這個指針定位到文件的任意位置。為了獲取從文件開始處到當前偏移的字節數,調用seekp()即可。在下面的例子中,程序將文件位置前移10個字節,然后調用 tellp()報告新位置:
ofstream fout("parts.txt");
fout.seekp(10); // 從0偏移開始前進 10 個字節
cout<<"new position: "<<fout.tellp(); // 顯示 10
你可以用下面的常量重新定位文ian指針:
ios::beg // 文件開始位置
ios::cur // 當前位置,例如: ios::cur+5
ios::end // 文件尾
第三步:讀寫數據
fstream 類為所有內建數據類型以及 std::string 和 std::complex 類型重載 << 和 >> 操作符。下面的例子示范了這些操作符的使用方法:
fstream logfile("log.dat");
logfile<<time(0)<<"danny"<<''\n''; // 寫一條新記錄
logfile.seekp(ios::beg); // 位置重置
logfile>>login>>user; // 讀取以前寫入的值
作者簡介
Danny Kalev 是一名通過認證的系統分析師和軟件工程師,專攻 C++ 和形式語言理論。1997 年到 2000 年期間,他是 C++ 標準委員會成員。最近他以優異成績完成了他在普通語言學研究方面的碩士論文。 業余時間他喜歡聽古典音樂,閱讀維多利亞時期的文學作品,研究 Hittite、Basque 和 Irish Gaelic 這樣的自然語言。其它興趣包括考古和地理。Danny 時常到一些 C++ 論壇并定期為不同的 C++ 網站和雜志撰寫文章。他還在教育機構講授程序設計語言和應用語言課程。
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