C++学习笔记(13)

203、文件操作-写入二进制文件

二进制文件以数据块的形式组织数据,把内存中的数据直接写入文件。

包含头文件:#include <fstream>

类:ofstream(output file stream)

ofstream 打开文件的模式(方式):

对于 ofstream,不管用哪种模式打开文件,如果文件不存在,都会创建文件。

ios::out 缺省值:会截断文件内容。

ios::trunc 截断文件内容。(truncate)

ios::app 不截断文件内容,只在文件未尾追加文件。(append)

ios::binary 以二进制方式打开文件。

操作文本文件和二进制文件的一些细节:

1)在 windows 平台下,文本文件的换行标志是"\r\n"。

2)在 linux 平台下,文本文件的换行标志是"\n"。

3)在 windows 平台下,如果以文本方式打开文件,写入数据的时候,系统会将"\n"转换成"\r\n";

读取数据的时候,系统会将"\r\n"转换成"\n"。 如果以二进制方式打开文件,写和读都不会进行转换。

4)在 Linux 平台下,以文本或二进制方式打开文件,系统不会做任何转换。

5)以文本方式读取文件的时候,遇到换行符停止,读入的内容中没有换行符;以二制方式读取文件

的时候,遇到换行符不会停止,读入的内容中会包含换行符(换行符被视为数据)。

6)在实际开发中,从兼容和语义考虑,一般:a)以文本模式打开文本文件,用行的方法操作它;b)

以二进制模式打开二进制文件,用数据块的方法操作它;c)以二进制模式打开文本文件和二进制文件,

用数据块的方法操作它,这种情况表示不关心数据的内容。(例如复制文件和传输文件)d)不要以文本

模式打开二进制文件,也不要用行的方法操作二进制文件,可能会破坏二进制数据文件的格式,也没有必

要。(因为二进制文件中的某字节的取值可能是换行符,但它的意义并不是换行,可能是整数 n 个字节

中的某个字节)

示例:

#include <iostream>

#include <fstream> // ofstream 类需要包含的头文件。

using namespace std;

int main()

{

// 文件名一般用全路径,书写的方法如下:

// 1)"D:\data\bin\test.dat" // 错误。

// 2)R"(D:\data\bin\test.dat)" // 原始字面量,C++11 标准。

// 3)"D:\\data\\bin\\test.dat" // 转义字符。

// 4)"D:/tata/bin/test.dat" // 把斜线反着写。

// 5)"/data/bin/test.dat" // Linux 系统采用的方法。

string filename = R"(D:\data\bin\test.dat)";

//char filename[] = R"(D:\data\bin\test.dat)";

// 创建文件输出流对象,打开文件,如果文件不存在,则创建它。

// ios::out 缺省值:会截断文件内容。

// ios::trunc 截断文件内容。(truncate)

// ios::app 不截断文件内容,只在文件未尾追加文件。(append)

// ios::binary 以二进制方式打开文件。

//ofstream fout(filename, ios::binary);

//ofstream fout(filename, ios::out | ios::binary);

//ofstream fout(filename, ios::trunc | ios::binary);

//ofstream fout(filename, ios::app | ios::binary);

ofstream fout;

fout.open(filename, ios::app | ios::binary);

// 判断打开文件是否成功。

// 失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux 平台下很常见。

if (fout.is_open() == false)

{

cout << "打开文件" << filename << "失败。\n"; return 0;

}

// 向文件中写入数据。

struct st_girl { // 超女结构体。

char name[31]; // 姓名。

int no; // 编号。

char memo[301]; // 备注。

double weight; // 体重。

}girl;

girl = { "西施",3,"中国历史第一美女。" ,45.8 };

fout.write((const char *)& girl, sizeof(st_girl)); // 写入第一块数据。

girl = { "冰冰",8,"也是个大美女哦。",55.2};

fout.write((const char*)&girl, sizeof(st_girl)); // 写入第二块数据。

fout.close(); // 关闭文件,fout 对象失效前会自动调用 close()。

cout << "操作文件完成。\n";

}

204、文件操作-读取二进制文件

包含头文件:#include <fstream>

类:ifstream

ifstream 打开文件的模式(方式):

对于 ifstream,如果文件不存在,则打开文件失败。

ios::in 缺省值。

ios::binary 以二进制方式打开文件。

示例:

#include <iostream>

#include <fstream> // ifstream 类需要包含的头文件。

using namespace std;

int main()

{

// 文件名一般用全路径,书写的方法如下:

// 1)"D:\data\bin\test.dat" // 错误。

// 2)R"(D:\data\bin\test.dat)" // 原始字面量,C++11 标准。

// 3)"D:\\data\\bin\\test.dat" // 转义字符。

// 4)"D:/tata/bin/test.dat" // 把斜线反着写。

// 5)"/data/bin/test.dat" // Linux 系统采用的方法。

string filename = R"(D:\data\bin\test.dat)";

//char filename[] = R"(D:\data\bin\test.dat)";

// 创建文件输入流对象,打开文件,如果文件不存在,则打开文件失败。。

// ios::in 缺省值。

// ios::binary 以二进制方式打开文件。

//ifstream fin(filename , ios::binary);

//ifstream fin(filename , ios::in | ios::binary);

ifstream fin;

fin.open(filename, ios::in | ios::binary);

// 判断打开文件是否成功。

// 失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux 平台下很常见。

if (fin.is_open() == false)

{

cout << "打开文件" << filename << "失败。\n"; return 0;

}

// 二进制文件以数据块(数据类型)的形式组织数据。

struct st_girl { // 超女结构体。

char name[31]; // 姓名。

int no; // 编号。

char memo[301]; // 备注。

double weight; // 体重。

}girl;

while (fin.read((char*)&girl, sizeof(girl)))

{

cout << "name=" << girl.name << ",no=" << girl.no <<

",memo=" << girl.memo << ",weight=" << girl.weight << endl;

}

fin.close(); // 关闭文件,fin 对象失效前会自动调用 close()。

cout << "操作文件完成。\n";

}

205、文件操作-随机存取

一、fstream 类

fstream 类既可以读文本/二进制文件,也可以写文本/二进制文件。

fstream 类的缺省模式是 ios::in | ios::out,如果文件不存在,则创建文件;但是,不会清空文件原

有的内容。

普遍的做法是:

1)如果只想写入数据,用 ofstream;如果只想读取数据,用 ifstream;如果想写和读数据,用 fst

ream,这种情况不多见。不同的类体现不同的语义。

2)在 Linux 平台下,文件的写和读有严格的权限控制。(需要的权限越少越好)

二、文件的位置指针

对文件进行读/写操作时,文件的位置指针指向当前文件读/写的位置。

很多资料用"文件读指针的位置"和"文件写指针的位置",容易误导人。不管用哪个类操作文件,

文件的位置指针只有一个。

1)获取文件位置指针

ofstream 类的成员函数是 tellp();ifstream 类的成员函数是 tellg();fstream 类两个都有,效果相

同。

std::streampos tellp();

std::streampos tellg();

2)移动文件位置指针

ofstream 类的函数是 seekp();ifstream 类的函数是 seekg();fstream 类两个都有,效果相同。

方法一:

std::istream & seekg(std::streampos _Pos);

fin.seekg(128); // 把文件指针移到第 128 字节。

fin.seekp(128); // 把文件指针移到第 128 字节。

fin.seekg(ios::beg) // 把文件指针移动文件的开始。

fin.seekp(ios::end) // 把文件指针移动文件的结尾。

方法二:

std::istream & seekg(std::streamoff _Off,std::ios::seekdir _Way);

在 ios 中定义的枚举类型:

enum seek_dir {beg, cur, end}; // beg-文件的起始位置;cur-文件的当前位置;end-文件的结尾

位置。

fin.seekg(30, ios::beg); // 从文件开始的位置往后移 30 字节。

fin.seekg(-5, ios::cur); // 从当前位置往前移 5 字节。

fin.seekg( 8, ios::cur); // 从当前位置往后移 8 字节。

fin.seekg(-10, ios::end); // 从文件结尾的位置往前移 10 字节。 三、随机存取

随机存取是指直接移动文件的位置指针,在指定位置读取/写入数据。

示例:

#include <iostream>

#include <fstream> // fstream 类需要包含的头文件。

using namespace std;

int main()

{

string filename = R"(D:\data\txt\test.txt)";

fstream fs;

fs.open(filename, ios::in | ios::out);

if (fs.is_open() == false)

{

cout << "打开文件" << filename << "失败。\n"; return 0;

}

fs.seekg(26); // 把文件位置指针移动到第 26 字节处。

fs << "我是一只傻傻的小菜鸟。\n";

/*string buffer;

while (fs >> buffer)

{

cout << buffer << endl;

}*/

fs.close(); // 关闭文件,fs 对象失效前会自动调用 close()。

cout << "操作文件完成。\n";

}

202、文件操作-打开文件的模式(方式)

一、写文件

如果文件不存在,各种模式都会创建文件。

ios::out 1)会截断文件;2)可以用 seekp()移动文件指针。

ios:trunc 1)会截断文件;2)可以用 seekp()移动文件指针。

ios::app 1)不会截断文件;2)文件指针始终在文件未尾,不能用 seekp()移动文件指针。

ios::ate 打开文件时文件指针指向文件末尾,但是,可以在文件中的任何地方写数据。

ios::in 打开文件进行读操作,即读取文件中的数据。

ios::binary 打开文件为二进制文件,否则为文本文件。

注:ate 是 at end 的缩写,trunc 是 truncate(截断)的缩写,app 是 append(追加)的缩写。

206、文件操作-缓冲区及流状态

一、文件缓冲区

文件缓冲区(缓存)是系统预留的内存空间,用于存放输入或输出的数据。

根据输出和输入流,分为输出缓冲区和输入缓冲区。

注意,在 C++中,每打开一个文件,系统就会为它分配缓冲区。不同的流,缓冲区是独立的。

程序员不用关心输入缓冲区,只关心输出缓冲区就行了。

在缺省模式下,输出缓冲区中的数据满了才把数据写入磁盘,但是,这种模式不一定能满足业务的需

求。

输出缓冲区的操作:

1)flush()成员函数

刷新缓冲区,把缓冲区中的内容写入磁盘文件。

2)endl

换行,然后刷新缓冲区。

3)unitbuf

fout << unitbuf;

设置 fout 输出流,在每次操作之后自动刷新缓冲区。

4)nounitbuf

fout << nounitbuf;

设置 fout 输出流,让 fout 回到缺省的缓冲方式。

二、流状态

流状态有三个:eofbit、badbit 和 failbit,取值:1-设置;或 0-清除。

当三个流状成都为 0 时,表示一切顺利,good()成员函数返回 true。

1)eofbit

当输入流操作到达文件未尾时,将设置 eofbit。

eof()成员函数检查流是否设置了 eofbit。

2)badbit

无法诊断的失败破坏流时,将设置 badbit。(例如:对输入流进行写入;磁盘没有剩余空间)。

bad()成员函数检查流是否设置了 badbit。

3)failbit

当输入流操作未能读取预期的字符时,将设置 failbit(非致命错误,可挽回,一般是软件错误,例如:

想读取一个整数,但内容是一个字符串;文件到了未尾)I/O 失败也可能设置 failbit。

fail()成员函数检查流是否设置了 failbit。

4)clear()成员函数清理流状态。

5)setstate()成员函数重置流状态。

示例 1:

#include <iostream>

#include <fstream> // ofstream 类需要包含的头文件。

#include <unistd.h>

using namespace std;

int main()

{

ofstream fout("/oracle/tmp/bbb.txt"); // 打开文件。

fout << unitbuf;

for (int ii = 0; ii < 1000; ii++) // 循环 1000 次。

{

fout << "ii=" << ii << ",我是一只傻傻傻傻傻傻傻傻傻傻傻傻傻傻的鸟。\n";

//fout.flush(); // 刷新缓冲区。

usleep(100000); // 睡眠十分之一秒。

}

fout.close(); // 关闭文件。

}

示例 2:

#include <iostream>

#include <fstream> // ifstream 类需要包含的头文件。

#include <string> // getline()函数需要包含的头文件。

using namespace std;

int main()

{

ifstream fin(R"(D:\data\txt\test.txt)", ios::in);

if (fin.is_open() == false) {

cout << "打开文件" << R"(D:\data\txt\test.txt)" << "失败。\n"; return 0;

}

string buffer;

/*while (fin >> buffer) {

cout << buffer << endl;

}*/

while (true) {

fin >> buffer;

cout << "eof()=" << fin.eof() << ",good() = " << fin.good() << ", bad() = " <<

fin.bad() << ", fail() = " << fin.fail() << endl;

if (fin.eof() == true) break;

cout << buffer << endl;

}

fin.close(); // 关闭文件,fin 对象失效前会自动调用 close()。

}

209、C++异常

一、异常的语法

1)捕获全部的异常

try

{

// 可能抛出异常的代码。

// throw 异常对象;

}

catch (...)

{

// 不管什么异常,都在这里统一处理。

}

2)捕获指定的异常

try

{

// 可能抛出异常的代码。

// throw 异常对象;

}

catch (exception1 e)

{

// 发生 exception1 异常时的处理代码。

}

catch (exception2 e)

{

// 发生 exception2 异常时的处理代码。

}

在 try 语句块中,如果没有发生异常,执行完 try 语句块中的代码后,将继续执行 try 语句块之后的

代码;如果发生了异常,用 throw 抛出异常对象,异常对象的类型决定了应该匹配到哪个 catch 语句块,

如果没有匹配到 catch 语句块,程序将调用 abort()函数中止。

如果 try 语句块中用 throw 抛出异常对象,并且匹配到了 catch 语句块,执行完 catch 语句块中的代

码后,将继续执行 catch 语句块之后的代码,不会回到 try 语句块中。

如果程序中的异常没有被捕获,程序将异常中止。

示例:

#include <iostream>

using namespace std;

int main(int argc, char* argv[])

{

try

{

// 可能抛出异常的代码。

int ii = 0;

cout << "你是一只什么鸟?(1-傻傻鸟;2-小小鸟)";

cin >> ii;

if (ii==1) throw "不好,有人说我是一只傻傻鸟。"; // throw 抛出 const char *类型的异常。

if (ii==2) throw ii;

// throw 抛出 int 类型的异常。

if (ii==3) throw string("不好,有人说我是一只傻傻鸟。"); // throw 抛出 string 类型的

异常。

cout << "我不是一只傻傻鸟,哦耶。\n";

}

catch (int ii)

{

cout << "异常的类型是 int=" << ii << endl;

}

catch (const char* ss)

{

cout << "异常的类型是 const char *=" << ss << endl;

}

catch (string str)

{

cout << "异常的类型是 string=" << str << endl;

}

//catch (...) // 不管什么异常,都在这里处理。

//{

// cout << "捕获到异常,具体没管是什么异常。\n";

//}

cout << "程序继续运行......\n"; // 执行完 try ... catch ...后,将继续执行程序中其它的代码。

}

相关推荐
小俊俊的博客7 分钟前
海康RGBD相机使用C++和Opencv采集图像记录
c++·opencv·海康·rgbd相机
_WndProc22 分钟前
C++ 日志输出
开发语言·c++·算法
薄荷故人_24 分钟前
从零开始的C++之旅——红黑树及其实现
数据结构·c++
m0_7482400224 分钟前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome
biter008826 分钟前
opencv(15) OpenCV背景减除器(Background Subtractors)学习
人工智能·opencv·学习
qq_4335545431 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++
努力学习编程的伍大侠36 分钟前
基础排序算法
数据结构·c++·算法
车轮滚滚__36 分钟前
uniapp对接unipush 1.0 ios/android
笔记
yuyanjingtao1 小时前
CCF-GESP 等级考试 2023年9月认证C++四级真题解析
c++·青少年编程·gesp·csp-j/s·编程等级考试
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习