C++开发基础——IO操作与文件流

一,基础概念

C++的IO操作是基于字节流,并且IO操作与设备无关,同一种IO操作可以在不同类型的设备上使用。

C++的流是指流入/流出程序的字节序列,在输入操作中数据从外部设备(键盘,文件,网络等)流入程序,在输出操作中数据从程序流向外部设备(控制台,文件,网络等)。

流充当了程序与外部设备之间的管道,使程序中的具体操作独立于各种外部设备。

常用的流:基础输入输出流,文件流,字符串流。

流的实例不仅包含普通的数据,还包含表示当前位置的数据。

在C++编程中,流的使用步骤如下:

1.实例化一个流对象。

2.将流对象关联到实际的外部设备(键盘,控制台,文件,网络等)。

3.调用流对象中提供的成员函数,完成数据的转换、传输等操作。

4.断开流对象与外部设备的关联,比如关闭文件。

5.释放流对象占用的内存资源。

流具有缓冲区,大部分时候,往流中写入数据后,流并不会马上把数据输出到指定目的地,为了提高性能,流先用缓冲区将数据存储起来,缓冲区达到一定大小后再输出到指定目的地。

刷新缓冲区的条件:

遇到触发的函数,如endl。

流对象离开作用域,被析构时。

流的缓冲区被写满。

显式调用flush()函数。

流对应的头文件有<ostream>, <fstream>等。

流支持的数据类型:数值类型,指针,char类型,std::string类,C风格字符串等。

std标准库包含预定义的流的实例,有cout,cin,cerr,clog等。

二,输出流

1.输出流的定义

对应运算符:operator<<            

含义:流中的数据输出到外部设备,"设备  <<  程序"。

<<运算符返回的是对一个流的引用,因此,可以连续调用多次<<运算符,来连续输出多段数据。

C++流遇到C风格的转义字符,比如“\n”,可以自动做解析。

“\n”和end都可以实现换行,但是“\n”只是换行,而end还会刷新缓存。

2.输出流的原始方法

(1).输出

put():写入单个字符。

write():写入字符数组。

代码样例,输出到控制台打印:

const char* test = "hello there";
cout.write(test, strlen(test));
cout.put('a');

(2).刷新缓冲区

flush()

代码样例,显式刷新流:

cout << "abc";
cout.flush();
cout << "de";
cout << "fgh";
cout << endl;

(3).判断流是否可用

good():可用时,返回true。

代码样例:

if (cout.good()){
    cout << "All good" << endl;
}

bad():发生致命错误时,返回true。

fail():最近一次操作失败时,返回true。

代码样例:

cout.flush();
if (cout.fail()){
    cerr << "Unable to flush to standard out" << endl;
}

3.输出流的操作算子

以下算子可以用来格式化输出流:

endl:输出一个行结束序列,并刷新缓存。

hex、oct、dec:以十六进制、八进制、十进制输出数字。

setw:设置输出数值型数据的字段宽度。

setfill:设置用于填充的字符。

setprecision:设置输出小数时的小数位数。

代码样例:

#include <chrono>
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
    int i = 123;
    cout << "The result is:" << setw(6) << i << endl;
    cout << "The result is:" << setfill('*') << setw(6) << i << endl;

    float j = 0.123456;
    cout << "The result is:" << setprecision(3) << j << endl;
}

运算结果:

The result is:   123
The result is:***123
The result is:0.123

三,输入流

1.输入流的定义

对应运算符:operator>>

含义:流中的数据从设备读入到程序中,"设备  >>  程序"。

2.输入流的原始方法

输入流也可以像输出流一样调用good()、bad()、fail()等方法,还可以调用eof()判断流的指针是否到达尾部。

(1).输入

get():读取单个字符。

read():读取字符数组。

(2).回退

unget():在读取的时候回退一个位置,将读取的前一个字符放回到流中。如果当前位置是流的起始位置,调用unget()会失败。

putback():和unget()一样支持回退,但是putback()可以指定放回的字符。

(3).预览

peek():预览调用get()后返回的下一个值。

(4).读取整行

getline():从输入流中获得一行数据,用法区别于C++中的std::getline()函数。

3.输入流的操作算子

以下算子可以用来格式化输入流:

hex、oct、dec:以十六进制、八进制、十进制读入数字。

skipws:输入时跳过空白字符,默认情况下为skipws。

noskipws:输入时读取空白字符作为标记。

代码样例:

#include <iostream>
#include <sstream>

int main()
{
    char c1, c2, c3;
    std::istringstream("a b c") >> std::skipws >> c1 >> c2 >> c3;
    std::cout << "skipws behavior:"
        " c1 = " << c1 <<
        " c2 = " << c2 <<
        " c3 = " << c3 << '\n';
    std::istringstream("a b c") >> std::noskipws >> c1 >> c2 >> c3;
    std::cout << "noskipws behavior:"
        " c1 = " << c1 <<
        " c2 = " << c2 <<
        " c3 = " << c3 << '\n';

    return 0;
}

运行结果:

skipws behavior: c1 = a c2 = b c3 = c
noskipws behavior: c1 = a c2 =   c3 = b

四,字符串流

对应头文件:<sstream>

常用字符串流:

std::ostringstream:将数据写入字符串

std::istringstream:从字符串读取数据

std::stringstream:双向操作字符串

1.字符串流支持的模式

ios::in:进行输入操作。
ios::out:进行输出操作。
ios::app:在字符串流后面追加。
ios::trunc:截断字符串。
ios::binary:用于二进制(原始字节)IO 操作,而不是基于字符的操作。
ios::ate:将指针移动到流的末尾。

2.字符串流的常用方法

字符输入流的操作:

operator>>:格式化输入。

get:读取单个字符。

read:读取字符数组。

getline:读取整行字符。

readsome:读取若干数量的字符。

peek:预览下一个字符。

unget:读取期间,回退一个字符。

tellg:返回流中的当前操作位置。

seekg:移动到流中的指定位置。

sync:与存储设备同步。

字符输出流的操作:

operator<<:格式化输出。

put:写入单个字符。

write:写入字符数组。

tellp:返回流中的当前操作位置。

seekp:移动到流中的指定位置。

flush:刷新数据到存储设备。

和状态相关的操作:

good()、bad()、fail()、eof():前面已经讲过。

setstate:设置状态。

clear:清除状态。

3.代码样例

#include <iostream>
#include <sstream>
#include <string>
#include <map>
using namespace std;

int main()
{
    string mystr = "how to study cpp very very good";
    map<string, int> myMap;

    stringstream ss(mystr);
    string Word;
    while (ss >> Word)
    {
        myMap[Word]++;
    }

    map<string, int>::iterator it;
    for (it = myMap.begin(); it != myMap.end(); it++)
    {
        cout << it->first << " -> "
             << it->second << "\n";
    }
    return 0;
}

运行结果:

cpp -> 1
good -> 1
how -> 1
study -> 1
to -> 1
very -> 2

五,文件流

头文件:<fstream>

常用文件流:

std::ofstream:将数据写入文件

std::ifstream:从文件读取数据

std::fstream:双向操作文件

std::ofstream, std::ifstream文件流的析构函数会自动关闭底层文件,所以操作完文件流以后不需要显式调用close()函数。

1.文件流支持的模式

ios::in:进行输入操作。
ios::out:进行输出操作。
ios::app:在文件流后面追加。
ios::trunc:截断文件内容。
ios::binary:用于二进制(原始字节)IO 操作,而不是基于字符的操作。
ios::ate:将指针移动到流的末尾。

文件流默认以文本模式打开文件流,如果指定了ios_base::binary,文件流将以二进制模式被打开。

2.文件流的常用方法

文件输入流的操作:

operator>>:格式化输入。

get:读取单个字符。

read:读取字符数组。

getline:读取整行字符。

readsome:读取若干数量的字符。

peek:预览下一个字符。

unget:读取期间,回退一个字符。

tellg:返回流中的当前操作位置。

seekg:移动到流中的指定位置。

sync:与存储设备同步。

文件输出流的操作:

operator<<:格式化输出。

put:写入单个字符。

write:写入字符数组。

tellp:返回流中的当前操作位置。

seekp:移动到流中的指定位置。

flush:刷新数据到存储设备。

和状态相关的操作:

good()、bad()、fail()、eof():前面已经讲过。

setstate:设置状态。

clear:清除状态。

3.代码样例

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    fstream obj;
    obj.open("test.txt", ios::out);
    obj << "Hello World";
    int pos1, pos2;

    pos1 = obj.tellp();
    cout << pos1 << endl;
    obj.seekp(0, ios::end);

    obj << "C++";
    pos2 = obj.tellp();
    cout << pos2 << endl;

    obj.close();
}

运行结果:

11
14

六,参考阅读

《C++高级编程》

https://zh.cppreference.com/w/cpp/io/basic_stringstream

https://zh.cppreference.com/w/cpp/io/basic_ifstream

https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp10_io.html

  • 25
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
 一、ASCII 输出   为了使用下面的方法, 你必须包含头文件<fstream.h>(译者注:在标准C++中,已经使用<fstream>取 代< fstream.h>,所有的C++标准头文件都是无后缀的。)。这是 <iostream.h>的一个扩展集, 提供有缓 冲的文件输入输出操作. 事实上, <iostream.h> 已经被<fstream.h>包含了, 所以你不必包含所有这两个 文件, 如果你想显式包含他们,那随便你。我们从文件操作类的设计开始, 我会讲解如何进行ASCII I/O 操作。如果你猜是"fstream," 恭喜你答对了! 但这篇文章介绍的方法,我们分别使用"ifstream"?和 "ofstream" 来作输入输出。   如果你用过标准控制台"cin"?和 "cout," 那现在的事情对你来说很简单。 我们现在开始讲输出部 分,首先声明一个类对象。 ofstream fout;   这就可以了,不过你要打开一个文件的话, 必须像这样调用ofstream::open()。 fout.open("output.txt");   你也可以把文件名作为构造参数来打开一个文件. ofstream fout("output.txt");   这是我们使用的方法, 因为这样创建和打开一个文件看起来更简单. 顺便说一句, 如果你要打开的文 件不存在,它会为你创建一个, 所以不用担心文件创建的问题. 现在就输出到文件,看起来和"cout"的操 作很像。 对不了解控制台输出"cout"的人, 这里有个例子。 int num = 150; char name[] = "John Doe"; fout << "Here is a number: " << num << " "; fout << "Now here is a string: " << name << " ";   现在保存文件,你必须关闭文件,或者回写文件缓冲. 文件关闭之后就不能再操作了, 所以只有在你 不再操作这个文件的时候才调用它,它会自动保存文件。 回写缓冲区会在保持文件打开的情况下保存文 件, 所以只要有必要就使用它。回写看起来像另一次输出, 然后调用方法关闭。像这样: fout << flush; fout.close();    现在你用文本编辑器打开文件,内容看起来是这样:   Here is a number: 150 Now here is a string: John Doe   很简单吧! 现在继续文件输入, 需要一点技巧, 所以先确认你已经明白了操作,对 "<<" 和">>" 比较熟悉了, 因为你接下来还要用到他们。继续…   二、ASCII 输入   输入和"cin" 很像. 和刚刚讨论的输出很像, 但你要考虑几件事情。在我们开始复杂的内容之前 , 先看一个文本:   12 GameDev 15.45 L This is really awesome!   为了打开这个文件,你必须创建一个in-stream对象,?像这样。 ifstream fin("input.txt");   现在读入前四行. 你还记得怎么用"<<" 操作符往里插入变量和符号吧?好,?在 "<<" (插入)?操作 符之后,是">>" (提取) 操作符. 使用方法是一样的. 看这个代码片段.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值