C++ Tutorials: C++ Language: Standard library: Input/output with files

本文介绍了C++中用于文件输入/输出的ofstream、ifstream和fstream类,详细阐述了如何打开、关闭文件,以及如何进行文本和二进制模式的读写操作。还讲解了文件状态检查、流定位、缓冲区同步等相关概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++官网参考链接:https://cplusplus.com/doc/tutorial/files/

输入/输出文件
C++提供了以下类来执行向文件输出和从文件中输入字符
*ofstream(ofstream:写入文件中的流类
*ifstream(ifstream:从文件中读取的流类
*fstream(fstream:从文件中读取和写入到文件中的流类。 
这些类直接或间接地派生自类istreamostream。我们已经使用过这些类类型的对象:cinistream类的对象,coutostream类的对象。因此,我们已经使用了与文件流相关的类。事实上,我们可以像使用cincout一样使用文件流,唯一不同的是我们必须将这些流与物理文件关联起来。让我们看一个例子:
// 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;
}

 

这段代码创建了一个名为example.txt的文件,并以与cout相同的方式在其中插入一句话,但使用的是文件流myfile
但让我们一步一步来: 

打开一个文件
对这些类的对象执行的第一个操作通常是将其关联到一个真实文件。这个过程被称为打开文件。一个打开的文件在程序中由一个表示(即,这些类中的一个对象;在前面的例子中,这是myfile),对这个对象执行的任何输入或输出操作都将应用到与它关联的物理文件。 
为了打开带有流对象的文件,我们使用它的成员函数open
open (filename, mode);
其中filename是表示要打开的文件名的字符串,mode是一个可选形参,由以下标志的组合组成:

ios::inOpen for input operations.
ios::outOpen for output operations.
ios::binaryOpen in binary mode.
ios::ate

Set the initial position at the end of the file.
If this flag is not set, 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.

(所有输出操作都在文件结束处执行,将内容追加到文件的当前内容。)

ios::trunc

If the file is opened for output operations and it already existed, its previous content is deleted and replaced by the new one.

(如果打开该文件进行输出操作,并且该文件已经存在,则会删除其以前的内容,并用新内容替换。)

所有这些标志都可以使用位操作符按位或(|)进行组合。例如,如果我们想以二进制模式打开example.bin文件来添加数据,我们可以通过调用成员函数open来实现:
ofstream myfile;
myfile.open ("example.bin", ios::out | ios::app | ios::binary);
ofstreamifstreamfstream的每个open成员函数都有一个默认模式,在没有第二个实参的情况下打开文件:

class(类)default mode parameter(默认模式形参)
ofstreamios::out
ifstreamios::in
fstreamios::in | ios::out

对于ifstreamofstream类,ios::inios::out被自动分别假定,即使一个mode不包含它们作为第二个实参传递给open成员函数(标志是组合的)。
对于fstream,只有在调用函数时没有为mode形参指定任何值时才应用默认值。如果用该形参中的任何值调用函数,则将覆盖默认的mode,而不是组合默认的mode
以二进制模式打开的文件流执行输入和输出操作独立于任何格式考虑。非二进制文件被称为文本文件,由于某些特殊字符(如换行符和回车符)的格式化,可能会发生一些转换。
由于在文件流上执行的第一个任务通常是打开文件,因此这三个类包括一个自动调用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。此成员函数接受刷新相关缓冲区并关闭文件:
myfile.close();
一旦调用了这个成员函数,就可以重用流对象来打开另一个文件,而该文件又可以被其他进程打开。
如果对象在仍然与打开的文件相关联的情况下被销毁,析构函数自动调用成员函数close。 

文本文件
文本文件流是那些在打开的mode中不包含ios::binary标志的文件流。这些文件被设计为存储文本,因此从/向它们输入或输出的所有值都可以进行一些格式化转换,这并不一定对应于它们的二进制文本值。 
对文本文件的写入操作的执行方式与对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;

从文件中读取也可以用与cin相同的方式执行:
// 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 ( getline (myfile,line) )
    {
      cout << line << '\n';
    }
    myfile.close();
  }

  else cout << "Unable to open file"; 

  return 0;

最后一个例子读取一个文本文件并在屏幕上打印出它的内容。我们已经创建了一个while循环,它使用getline逐行读取文件。getline返回的值是流对象本身的引用,当作为布尔表达式计算时(如在这个while循环中),如果流已准备好进行更多操作,则为true;如果到达文件结束发生其他错误,则为false

检查状态标志
以下成员函数用于检查流的特定状态(它们都返回bool值): 
bad()
如果读写操作失败,返回true。例如,当我们试图写入一个未打开的文件时,或者当我们试图写入的设备没有剩余空间时。
fail()
在与bad()相同的情况下返回true,但也在发生格式错误的情况下返回true,例如当我们试图读取整数时提取了字母字符。
eof()
如果打开用于读取的文件已到达文件结束,则返回true
good()
它是最通用的状态标志:在调用前面任何函数都会返回true的情况下,它返回false。注意,good和bad并不是完全相反的(good一次检查更多的状态标志)。
成员函数clear()可用于重置状态标志

获取和写入流定位
所有I/O流对象在内部至少保留一个内部位置
istream一样,ifstream保留了一个内部的读取位置,该位置是下一个输入操作中要读取的元素的位置。 
ostream一样,ofstream保留一个内部的写入位置,即下一个元素必须写入的位置。
最后,fstream,保留读取和写入的位置,就像iostream
这些内部流位置指向流中执行下一个读或写操作的位置。可以使用以下成员函数观察和修改这些位置:
tellg()tellp()
这两个不带形参的成员函数返回成员类型streampos的值,该类型表示当前的读取位置在tellg的情况下)或写入位置在tellp的情况下)。
seekg()和seekp()
这些函数允许更改读取或写入定位的位置。两个函数都用两个不同的原型重载。第一种形式是:
seekg ( position );
seekp ( position );
使用这个原型,流指针被更改为绝对位置position(从文件开始处计算)。此形参的类型是streampos,与函数tellg和tellp返回的类型相同。
这些函数的另一种形式是:
seekg ( offset, direction );
seekp ( offset, direction );
使用这个原型,读取或写入位置被设置为相对于由形参direction确定的特定点的偏移(offset)值。offset为streamoff类型。direction的类型seekdir,这是一个枚举类型,确定从哪里开始计算偏移(offset)值的点,它可以采用以下值中的任何一个:

ios::begoffset counted from the beginning of the stream(从流的开始位置计算偏移量)
ios::curoffset counted from the current position(从流的当前位置计算偏移量)
ios::endoffset counted from the end of the stream(从流的结束位置计算偏移量)

下面的例子使用我们刚刚看到的成员函数来获取文件的大小:
// obtaining file size
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  streampos begin,end;
  ifstream myfile ("example.bin", ios::binary);
  begin = myfile.tellg();
  myfile.seekg (0, ios::end);
  end = myfile.tellg();
  myfile.close();
  cout << "size is: " << (end-begin) << " bytes.\n";
  return 0;

注意我们为变量begin和end所使用的类型:
streampos size;
streampos是用于缓冲区和文件定位的特定类型,是file.tellg()返回的类型。此类型的值可以安全地从相同类型的其他值中减去,也可以转换为大到足以包含文件大小的整数类型
这些流定位函数使用两种特殊类型:streamposstreamoff。这些类型也被定义为流类的成员类型:

Type(类型)Member type(成员类型)Description(描述)
streamposios::pos_type

Defined as fpos<mbstate_t>.
It can be converted to/from streamoff and can be added or subtracted values of these types.

 (定义为fpos<mbstate_t>。)

(它可以被转换为streamoff,或者由streamoff转换而来,并且可以加或减去这些类型的值。)

streamoffios::off_type

It is an alias of one of the fundamental integral types (such as int or long long).

(它是一种基本整型类型(例如int或long long)的别名。)

上面的每个成员类型都是其等价非成员的别名(它们是完全相同的类型)。用哪一个并不重要。成员类型更泛型,因为它们在所有流对象上是相同的(甚至在使用奇异类型的字符的流上),但由于历史原因,非成员类型在现有代码中广泛使用。

二进制文件
对于二进制文件,使用提取和插入操作符(<<和>>)和getline之类的函数读写数据是低效的,因为我们不需要格式化任何数据,而且数据可能没有按行格式化。 
文件流包括两个专门为按顺序读写二进制数据而设计的成员函数readwrite。第一个(write)是ostream的成员函数(由ofstream继承)。readistream的成员函数(由ifstream继承)。fstream类的对象两者都有。他们的原型是:
write ( memory_block, size );
read ( memory_block, size );
其中memory_block类型为char*(指向char的指针),表示存储已读数据元素的字节数组的地址,或要写入的数据元素的地址。size形参是一个整数值,指定要从内存块读或写的字符数。 
// reading an entire binary file
#include <iostream>
#include <fstream>
using namespace std;

int main () {
  streampos size;
  char * memblock;

  ifstream file ("example.bin", 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 entire file content is in memory";

    delete[] memblock;
  }
  else cout << "Unable to open file";
  return 0;
}

在本例中,整个文件被读取并存储在一个内存块中。让我们来看看这是如何做到的:
首先,打开文件时带有ios::ate标志,这意味着读取指针将定位在文件结束处。这样,当我们调用成员tellg()时,我们将直接获得文件的大小。 
一旦我们获得了文件的大小,我们请求分配一个足够大的内存块来容纳整个文件:
memblock = new char[size];
在这之后,我们继续设置文件开头的读取位置(记住,我们是用这个在定位在文件的结束指针打开文件的),然后读取整个文件,最后关闭它:
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
此时,我们可以对从文件中获得的数据进行操作。但是我们的程序只是宣布文件的内容在内存中,然后结束。 

缓冲区和同步
当我们操作文件流时,它们与streambuf类型的内部缓冲区对象相关联。该缓冲区对象可以表示一个内存块,该内存块充当流和物理文件之间的中介。例如,对于ofstream,每次调用成员函数put(它写入单个字符)时,可以将该字符插入这个中间缓冲区,而不是直接写入与流相关的物理文件。
操作系统还可以定义用于文件读写的其他缓冲层。
刷新缓冲区时,将其中包含的所有数据写入物理介质(如果它是输出流)。这个过程被称为同步,在以下任何情况下发生:
*当文件关闭时:在关闭文件之前,所有尚未被刷新的缓冲区被同步,所有挂起的数据被写入或读取到物理介质。
*当缓冲区满时:缓冲区有一定的大小。当缓冲区满时,它会自动同步。
*显式地,使用操纵符:当某些操纵符在流上使用时,将发生显式同步。这些操纵符是:flushendl。 
*显式地,使用成员函数sync():调用流的成员函数sync()导致立即同步。如果流没有相关联的缓冲区或在失败的情况下,此函数返回一个等于-1的int值。否则(如果流缓冲区成功同步)它返回0

该资源不适合C、C++初学者,可作为C++高手向大师级进化的参考书。 内容: ... 17 Library introduction 17.1 General 17.2 The C standard library 17.3 Definitions 17.4 Additional definitions 17.5 Method of description (Informative) 17.6 Library-wide requirements 18 Language support library 18.1 General 18.2 Types 18.3 Implementation properties 18.4 Integer types 18.5 Start and termination 18.6 Dynamic memory management CONTENTS v c ISO/IEC N3000=09-0190 18.7 Type identification 18.8 Exception handling 18.9 Initializer lists 18.10Other runtime support 19 Diagnostics library 456 19.1 General 19.2 Exception classes 19.3 Assertions 19.4 Error numbers 19.5 System error support 20 General utilities library 20.1 General 20.2 Requirements 20.3 Utility components 20.4 Compile-time rational arithmetic 20.5 Tuples 20.6 Metaprogramming and type traits 20.7 Function objects . 520 20.8 Memory 541 20.9 Time utilities 583 20.10Date and time functions 596 20.11Class type_index 596 21 Strings library 599 21.1 General 599 21.2 Character traits 599 21.3 String classes 605 21.4 Class template basic_string 608 21.5 Numeric Conversions 635 21.6 Null-terminated sequence utilities . 636 22 Localization library 640 22.1 General 640 22.2 Header <locale> synopsis 640 22.3 Locales 641 22.4 Standard locale categories . 653 22.5 Standard code conversion facets 693 22.6 C Library Locales 695 23 Containers library 696 23.1 General 696 23.2 Container requirements 696 23.3 Sequence containers 719 23.4 Associative containers . 758 23.5 Unordered associative containers . 776 24 Iterators library 791 24.1 General 791 24.2 Iterator requirements 791 CONTENTS vi c ISO/IEC N3000=09-0190 24.3 Header <iterator> synopsis 796 24.4 Iterator primitives 799 24.5 Iterator adaptors . 802 24.6 Stream iterators . 816 25 Algorithms library 825 25.1 General 825 25.2 Non-modifying sequence operations 835 25.3 Mutating sequence operations 839 25.4 Sorting and related operations 848 25.5 C library algorithms 862 26 Numerics library 864 26.1 General 864 26.2 Numeric type requirements . 864 26.3 The floating-point environment 865 26.4 Complex numbers 866 26.5 Random number generation . 876 26.6 Numeric arrays 920 26.7 Generalized numeric operations 940 26.8 C Library 944 27 Input/output library 949 27.1 General 949 27.2 Iostreams requirements . 950 27.3 Forward declarations 950 27.4 Standard iostream objects 952 27.5 Iostreams base classes . 954 27.6 Stream buffers 972 27.7 Formatting and manipulators 982 27.8 String-based streams 1009 27.9 File-based streams 1021 28 Regular expressions library 1036 28.1 General 1036 28.2 Definitions 1036 28.3 Requirements 1037 28.4 Header <regex> synopsis 1039 28.5 Namespace std::regex_constants 1045 28.6 Class regex_error 1048 28.7 Class template regex_traits 1048 28.8 Class template basic_regex 1051 28.9 Class template sub_match 1056 28.10Class template match_results 1062 28.11Regular expression algorithms 1066 28.12Regular expression Iterators . 1070 28.13Modified ECMAScript regular expression grammar 1076 29 Atomic operations library 1079 29.1 General 1079 29.2 Header <atomic> synopsis 1079 CONTENTS vii c ISO/IEC N3000=09-0190 29.3 Order and Consistency . 1082 29.4 Lock-free Property 1084 29.5 Atomic Types 1085 29.6 Operations on Atomic Types 1094 29.7 Flag Type and Operations 1098 29.8 Fences . 1099 30 Thread support library 1101 30.1 General 1101 30.2 Requirements 1101 30.3 Threads 1102 30.4 Mutual exclusion . 1107 30.5 Condition variables 1121 30.6 Futures 1129 A Grammar summary 1149 A.1 Keywords 1149 A.2 Lexical conventions 1149 A.3 Basic concepts 1154 A.4 Expressions . 1154 A.5 Statements . 1158 A.6 Declarations . 1159 A.7 Declarators . 1162 A.8 Classes . 1164 A.9 Derived classes 1165 A.10 Special member functions 1165 A.11 Overloading . 1165 A.12 Templates 1166 A.13 Exception handling 1167 A.14 Preprocessing directives 1167 B Implementation quantities 1169 C Compatibility 1171 C.1 C++ and ISO C 1171 C.2 Standard C library 1181 D Compatibility features 1185 D.1 Increment operator with bool operand . 1185 D.2 static keyword . 1185 D.3 Access declarations 1185 D.4 Implicit conversion from const strings . 1185 D.5 register keyword 1185 D.6 C standard library headers . 1185 D.7 Old iostreams members 1186 D.8 char* streams 1187 D.9 Binders 1196 D.10 auto_ptr 1198 E Cross references 1201 Index 1218 CONTENTS viii ISO/IEC N3000=09-0190 Index of Grammar Productions 1243 Index of Library Names 1246 Index of Implementation Defined Behavior 1280
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值