c++ 定义了ifstream, ofstream, fstream类用于文件处理和操作文件,这些类定义在头文件<fstream>中。

c++使用“流”来描述数据流动,数据流向程序,则为input stream(输入流),反之为output stream输出流。

1.文本文件的读写操作。

写入文件

#include <iostream>
#include <fstream>
using namespace std;int main()
{ofstream output;output.open("score.txt");   // open a fileoutput << "zhangjun" << " " << 'S' << " " << 90 << endl;output << "hehe" << " " << 'L' << " " << 88 << endl;output.close();  // close the filecout << "Done" << endl;    return 0;
}

如果文件已经存在,再次打开的话,文件的内容会被清除。

读取文件:

#include <iostream>
#include <fstream>
using namespace std;int main()
{ifstream input;input.open("score.txt");string name;char med;int score;input >> name >> med >> score;cout << "name is " << name << " char is " << med << " score is " << score << endl;input >> name >> med >> score;cout << "name is " << name << " char is " << med << " score is " << score << endl;input.close();return 0;
}

关于空格:

读取的数据中是以空格作为分割。如果写入的也有空格,则会导致独处的数据有问题。

2. 检测文件是否存在

fail()函数用于检测文件是否存在!打开文件后可以用fail()函数判断

对上面的代码添加文件检测是否存在:

#include <iostream>
#include <fstream>
using namespace std;int main()
{ifstream input;input.open("score.txt");// if the file existif(input.fail()){cout << "the file not exist";return 0;}string name;char med;int score;input >> name >> med >> score;cout << "name is " << name << " char is " << med << " score is " << score << endl;input >> name >> med >> score;cout << "name is " << name << " char is " << med << " score is " << score << endl;input.close();return 0;
}

3.检测文件结束

在不知道文件有多少行又想读取读取全部数据的话,需要检测文件的结束位置

(1).eof()函数

   ifstream input;input.open("filename");while(!input.eof()){// read data from file;input >> number;if(input.eof()) break;    // 每读完一次数据,立即检测一次 //  other operation .....}

(2)通过input>>返回的值判断

        while(input>>number){// read data from file;} 

input>>number读入数据返回的是一个对象,否则返回的是NULL,据此可以判断文件末尾

注: c++中输入输出流的构造函数参数为c字符串,所以如果文件名问string,要转换c_str()

string filename;
cin >> filename;
input.open(filename.c_str());

4.函数getline, get, put

流提取运算符读取数据,只能以空格作为分隔符,如果读取的数据中含有空格,则应该怎么读取

getline() : <iostream> , 函数参数getline(ifstream, int/string data, delimitChar)

get()    // 只能读写单个字符

put()     // 只能读写单个字符

例如读取: New  york#New  Mexico# India

 string citywhile(!input.eof())
{getline(input, city, '#');   // 注意delimitChar! 是Char!cout << city << endl;
}

5.fstream和文件打开模式

fstream创建既能写入又能读出的文件

打开文件的模式:

ios::in     读取模式打开文件

ios::out    写入文件模式

ios::app    追加模式

ios::trunc   如果文件已经存在,丢弃文件内容

ios::binary    二进制输入输出

实例:创建一个文件,写入数据并关闭,再次打开追加数据

#include <iostream>
#include <fstream>
using namespace std;int main()
{fstream inout;// creat a fileinout.open("city.txt", ios::out);   //打开文件的模式// write citiesinout << "Dalloa" << " " << "Hoston" << " " << "Anlantas" << " ";inout.close();// open file inout.open("city.txt", ios::out | ios::app);// write a lineinout << "Swadas" << " " << "Austin" << " " << "Chicago" ;inout.close();// read the fileinout.open("city.txt", ios::in);string city;while(!inout.eof()){inout >> city;cout << city << endl;} inout.close();return 0;
}

检测流状态:

c++以提供的检测流状态的函数:
eof()

fail()   文件打开是否成功

bad()

good()

clear()

#include <iostream>
#include <fstream>
using namespace std;void showState(fstream&);
int main()
{fstream inout;//creat an output fileinout.open("temp.txt", ios::out);inout << "Dallas";cout << "Normal operation." << endl;inout.close();showState(inout);inout.open("temp.txt", ios::in);string city;inout >> city;cout << "End of file" << endl;showState(inout);inout.close();return 0;
}void showState(fstream& a)
{cout << "stream state: " << endl;cout << "eof(): " << a.eof() << endl;cout << "fail(): " << a.fail() << endl;cout << "bad(): " << a.bad() << endl;cout << "good: " << a.good() << endl;
}

6.二进制输入输出

二进制文件输入输出打开方式

文件可以分为文本文件和二进制文件两类

文本文件:能被文本编辑器处理的文件称为文本文件。 在c++中,扩展名为.txt

二进制文件:非文本文件都称为二进制文件。只能由计算机程序读取处理,在c++中扩展名为.dat, 处理二进制文件效率更高

为了读写二进制文件,必须对流对象使用read(), write()函数

1.write()函数

streamObject.write(const char*, int size): char*: 写入的字符数组       size:写入的字节数

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int main()
{fstream binaryio;     binaryio.open("city.dat", ios::out | ios::binary);  // 二进制写入, 二进制文件 .dat string s("Atlant");binaryio.write(s.c_str(), s.size());    // 转化为c字符串binaryio.close();cout << "Done" << endl;   return 0;
}

非字符数据的写入,使用reinterpret_cast运算符实现将一个指针类型转化为与其不相关的指针类型,它只是进行指针值的二进制复制,并不改变指针指向的数据。

reinterpret_cast<datatype*>(address)       允许将任何指针转换为任何其他指针类型

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int main()
{fstream binaryio;     binaryio.open("temp.dat", ios::out | ios::binary);  // 二进制写入, 二进制文件 .dat int value = 199;binaryio.write(reinterpret_cast<char*>(&value), sizeof(value));  binaryio.close();cout << "Done" << endl;   return 0;
}

2 read()函数

streamObject.read(char* address, int size)     // size指定可以读取的最大字节数, gcount() 获取实际读取字节数

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int main()
{fstream binaryio;     binaryio.open("city.dat", ios::in | ios::binary);  // 二进制读取, 二进制文件 .dat char s[10]; binaryio.read(s, 10);s[binaryio.gcount()] = '\0';   // gcount()获取实际读取的字节数  // 设置字符串的末尾'\0' cout << s << endl;binaryio.close();return 0;
}

读取整数;
文件temp.dat中存储的整数转变为二进制字节,现在读取这些字节,转化为整数

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int main()
{fstream binaryio;     binaryio.open("temp.dat", ios::in | ios::binary);  // 二进制读取, 二进制文件 .dat int value; binaryio.read(reinterpret_cast<char*>(&value), sizeof(value));cout << value << endl;binaryio.close();return 0;
}

3. 二进制数组IO

可以使用reinterpret_cast将任意类型的数据转变为二进制字节,也可以将二进制字节转化为任意类型的数据

如:将double数组写入二进制文件,然后再读取出来

#include <iostream>
#include <fstream>
#include <string>
using namespace std;int main()
{const int SIZE = 5;fstream binaryio;// 想数组中写入数据binaryio.open("array.dat", ios::out | ios::binary);double array[SIZE] = {2.3, 4, 3.8, 3.0, 11.11};binaryio.write(reinterpret_cast<char*>(&array), sizeof(array));binaryio.close();// 读取文件中的数据binaryio.open("array.dat", ios::in | ios::binary);double result[SIZE];binaryio.read(reinterpret_cast<char*>(&result), sizeof(result));binaryio.close();// display arrayfor(int i=0; i<SIZE; i++){cout << result[i] << " ";} cout << endl;return 0;
}

二进制对象IO

如何向二进制文件写入对象,以及从二进制文件读出

定义一个Student类, 将类写入文件和从文件中读出

代码:

student.h

#include <iostream>
#include <string>using namespace std;#ifndef STUDENT_H
#define STUDENT_H
class Student
{private:char firstName[25];char mid;    // 中间名char lastName[25];int score;public:Student();   // 无参构造函数Student(const string& firstName, const char mid, const string& lastName, int score);  // 有参构造函数 // 定义访问器和更改器void setFirstName(const string& firstName);void setMid(const char mid);void setLastName(const string& lastName);void setScore(int score);string getFirstName() const;char getMid() const;string getLastName() const;int getScore() const;
};#endif

student.cpp

#include <iostream>
#include <string>
#include <cstring>
#include "E:\back_up\code\c_plus_code\chapter5\external_file\student..h"
using namespace std;Student::Student()
{// all the data remain default value;
}
Student::Student(const string& firstName, const char mid, const string& lastName, int score)
{setFirstName(firstName);setMid(mid);setLastName(lastName); setScore(score);
}// mutator
void Student::setFirstName(const string& firstName)
{strcpy(this->firstName, firstName.c_str());    // string 类型的值复制到char[]
}void Student::setMid(const char mid)
{this->mid = mid;
}void Student::setLastName(const string& lastName)
{strcpy(this->lastName, lastName.c_str());      // strcpy()函数的参数:,char[], string.c_str()才可以
}void Student::setScore(int score)
{this->score = score;
}string Student::getFirstName() const
{return string(firstName);      // 将char[]转换为string
}char Student::getMid() const
{return mid;
}string Student::getLastName() const
{return string(lastName);     //  }int Student::getScore() const
{return score;
}
// accessor

main.cpp

#include <iostream>
#include <fstream>
#include <string>
#include "E:\back_up\code\c_plus_code\chapter5\external_file\student..h"
using namespace std;void displayStudent(const Student&);
int main()
{Student student1("Jhoon", 'K', "jerry", 90);     Student student2("Mary", 'L', "Charlotte", 100);Student student3("Koeras", 'B', "Long", 78);Student student4("Maksa", 'C', "short", 90);fstream binaryio;binaryio.open("student.dat", ios::out | ios::binary);   // 创建文件,写入数据 binaryio.write(reinterpret_cast<char*>(&student1), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student2), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student3), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student4), sizeof(Student));binaryio.close();binaryio.open("student.dat", ios::in | ios::binary);   // 这种读取数据的方法,文件指针自动下移 Student student;binaryio.read(reinterpret_cast<char*>(&student), sizeof(Student));displayStudent(student);binaryio.read(reinterpret_cast<char*>(&student), sizeof(Student));displayStudent(student); return 0;
}void  displayStudent(const Student& student)
{cout << student.getFirstName() << " " << student.getMid() << " " << student.getLastName() << " " << student.getScore() << endl;
}

注:

student类中lastName和firstName的数据类型为固定字符长度的数组,char[25],  而不用string, 是因为在reinterpret(char*, size)时。size = sizeof(Student)保证每个学生记录大小相同,保证正确读取学生数据,如果采用string则不能保证。

char[] 与string类型之间的转化:

string(char[])  类型转化

strcpy(string, char[].c_str())   // 值复制

4. 随机访问文件

使用seekg()函数和seekp()函数移动文件指针到任意位置。

文件由字节序列组成,操作系统中会维护一个文件指针的特殊标记,指向序列中的某个位置,读写操作都是从文件指针指向的位置处进行。

文件的访问分为:

1. 顺序访问文件        文件指针位于文件开始的地方。向后移动

2.随机访问文件        读取文件的数据时,如果想跳过前面的数据项,访问某一项数据,可以采用随机访问文件。‘

c++允许对流对象使用seekp()和seekg()函数,移动文件的指针到任意的位置

seekp() : seek put  用于输出流

seekg() : seek get  用于输入流

seekg(pos): 将指针移动到绝对位置pos

seekg(long a, pos):  pos是相对位置, a是偏移量, 注意偏移量的单位是字节      pos: :ios:beg, ios::end, ios::cur

tellp:

tellg: 返回文件指针的当前位置

修改上面的student代码

只对main.cpp作如下修改:

#include <iostream>
#include <fstream>
#include <string>
#include "E:\back_up\code\c_plus_code\chapter5\external_file\student..h"
using namespace std;void displayStudent(const Student&);
int main()
{Student student1("Jhoon", 'K', "jerry", 90);     Student student2("Mary", 'L', "Charlotte", 100);Student student3("Koeras", 'B', "Long", 78);Student student4("zhuwen", 'F', "short", 90);Student student5("xiang", 'F', "short", 90);Student student6("gouhao", 'S', "short", 90);Student student7("crappple", 'C', "short", 90);fstream binaryio;binaryio.open("student.dat", ios::out | ios::binary);   // 创建文件,写入数据 binaryio.write(reinterpret_cast<char*>(&student1), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student2), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student3), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student4), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student5), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student6), sizeof(Student));binaryio.write(reinterpret_cast<char*>(&student7), sizeof(Student));binaryio.close();binaryio.open("student.dat", ios::in | ios::binary);   // 打开文件,指针这时位于文件起始的位置 cout << "current position is " << binaryio.tellg() << endl;   // 当前文件中指针的位置Student student;// 读取第三个数据,跳过前两个binaryio.seekg(2*sizeof(Student));  // 将指针向后移动两个数据项cout << "current position is " << binaryio.tellg() << endl;   // 当前文件中指针的位置binaryio.read(reinterpret_cast<char*>(&student), sizeof(Student));   // 读取的是第三项数据 displayStudent(student);cout << "current position is " << binaryio.tellg() << endl;   // 当前文件中指针的位置// 指针的当前位置binaryio.seekg(2*sizeof(Student), ios::cur); // 读取第七条数据  // 偏移量单位是字节,所以向后移动两项数据,偏移量应该是n*sizeof(Student)  cout << "Current position is " << binaryio.tellg() << endl;binaryio.read(reinterpret_cast<char*>(&student), sizeof(Student));displayStudent(student); cout << "Current position is " << binaryio.tellg() << endl;return 0;
}void  displayStudent(const Student& student)
{cout << student.getFirstName() << " " << student.getMid() << " " << student.getLastName() << " " << student.getScore() << endl;
}

运行结果:

分析:

1. 首先将七个student对象依次写进二进制文件

2. 打开二进制文件,此时文件指针位于文件的开头,指向的是第一个数据, position = 0

3. 将文件指针向后移动两个数据项     binaryio.seekg(2*sizeof(Student));    position = 112

4.读取数据项,读到的是第三个数据项,可以看到读取完毕后文件指针后移到下一个数据项, position = 168

5.再将文件指针从当前位置向后移动两个位置,读取数据项

6. 更新文件:

可以使用组合模式打开文件。如:按照读写模式打开一个二进制文件,对文件进行更新

对上面的程序做出修改:

#include <iostream>
#include <fstream>
#include <string>
#include "E:\back_up\code\c_plus_code\chapter5\external_file\student..h"
using namespace std;void displayStudent(const Student&);
int main()
{   fstream binaryio;binaryio.open("student.dat", ios::out | ios::in | ios::binary);   // 以读写模式打开二进制文件 Student student_new;binaryio.seekg(sizeof(Student));   // 文件指针后移一个位置binaryio.read(reinterpret_cast<char*>(&student_new), sizeof(Student));displayStudent(student_new);student_new.setFirstName("SHI");student_new.setLastName("gououou");student_new.setScore(100);binaryio.seekg(sizeof(Student));    // 因为读完数据后文件指针下移,所以需要将文件指针拉回到原处再写入修改后的数据,达到文件更新的目的 binaryio.write(reinterpret_cast<char*>(&student_new), sizeof(student_new)); binaryio.close();binaryio.open("student.dat", ios::in | ios::binary);   // 打开文件,指针这时位于文件起始的位置 Student student;binaryio.seekg(sizeof(Student));  // 读取修改后的数据  定位 //cout << "current position is " << binaryio.tellg() << endl;   // 当前文件中指针的位置binaryio.read(reinterpret_cast<char*>(&student), sizeof(Student));   // 读取的是第三项数据 displayStudent(student);//cout << "current position is " << binaryio.tellg() << endl;   // 当前文件中指针的位置binaryio.close(); return 0;
}void  displayStudent(const Student& student)
{cout << student.getFirstName() << " " << student.getMid() << " " << student.getLastName() << " " << student.getScore() << endl;
}

需要注意的是对文件修改时,必须保证指针指向数据的正确性,否则数据没有修改,却把别的数据给覆盖了

c++笔记(10) 文件输入输出相关推荐

  1. python 学习笔记 5 -- 文件输入输出

    本文主要介绍python下的文件输入输出操作,python的文件操作简单易用-通过本文相信你可以熟练掌握file和pickle这两种输入输出操作! 1.文件 你可以通过创建一个file类的对象来打开一 ...

  2. java web 文件上传_Javaweb学习笔记10—文件上传与下载

    今天来讲javaweb的第10阶段学习.文件的上传与下载,今天主要说的是这个功能的实现,不用说了,听名字就是外行人也知道肯定很重要啦. 老规矩,首先先用一张思维导图来展现今天的博客内容. ps:我的思 ...

  3. APUE读书笔记-03文件输入输出(2)

    转载于:https://blog.51cto.com/quietheart/759609

  4. 史上最牛最强的linux学习笔记 10.shell基础

    史上最牛最强的linux学习笔记 10.shell基础 写在最前面: 本文是基于某站的视频学习所得,第一个链接如下: https://www.bilibili.com/video/BV1mW411i7 ...

  5. thinkphp学习笔记10—看不懂的路由规则

    原文:thinkphp学习笔记10-看不懂的路由规则 路由这部分貌似在实际工作中没有怎么设计过,只是在用默认的设置,在手册里面看到部分,艰涩难懂. 1.路由定义 要使用路由功能需要支持PATH_INF ...

  6. SpringMVC:学习笔记(10)——整合Ckeditor且实现图片上传

    SpringMVC:学习笔记(10)--整合Ckeditor且实现图片上传 配置CKEDITOR 精简文件 解压之后可以看到ckeditor/lang下面有很多语言的js,如果不需要那么多种语言的,可 ...

  7. Python 网络爬虫笔记10 -- Scrapy 使用入门

    Python 网络爬虫笔记10 – Scrapy 使用入门 Python 网络爬虫系列笔记是笔者在学习嵩天老师的<Python网络爬虫与信息提取>课程及笔者实践网络爬虫的笔记. 课程链接: ...

  8. C语言笔记:格式化输入输出(fprintf、fscanf、sscanf...)

    C语言笔记:格式化输入输出(fprintf.fscanf.sscanf-) 包含以下函数的基本库:stdlib.h fprintf int fprintf(FILE *stream, const ch ...

  9. android中资源文件的两种访问方式,Android_Android学习笔记-保存文件(Saving Files),Android设备有两种文件存储区域 - phpStudy...

    Android学习笔记-保存文件(Saving Files) Android设备有两种文件存储区域: 内部存储和外部存储 ("internal" and "externa ...

最新文章

  1. Python Tesseract 图片识别-小操练
  2. 题目1178:复数集合
  3. 大数据WEB阶段(六)MySql详解(二)
  4. 使用 HttpWebRequest 向网站提交数据
  5. 米家扫地机器人充满电需要多长时间_米家扫地机器人充满电后能工作多久?
  6. php正则如何使用 1,PHP正则表达式使用详解(1)
  7. RTT 使用menuconfig 和cubeMux 在移植过来的模板工程上增加一个串口2
  8. GitHub如何在README.md文件中插入图片
  9. apk私钥_移动安全(二)|APK打包流程及签名安全机制初探
  10. VMware资源集合,分享一波
  11. 190507每日一句
  12. ASP.net的简单认识
  13. P8700和T9600对比测试
  14. 前端开发step1,2,3
  15. 医学四视图-005-四视图加按钮
  16. 一场雨我们的见证了什么?
  17. 计算机导师团队如何发邮件,研究生给导师发邮件的3个模板
  18. socket编程基础2(socket API函数介绍)
  19. C# 理解Thread.Sleep()方法
  20. vscode中安装开发html5中需要的插件

热门文章

  1. Netty工作笔记0055---Unpooled应用实例1
  2. java框架实例---自定义标签实例
  3. EJB3.0学习笔记---MDBbean--区分P2P模式和Pub/Sub模式的示例
  4. MessageBox和AfxMessageBox函数的区别
  5. linux下gdb调试程序
  6. 如何将一棵树转换成二叉树
  7. linux下的C语言开发(线程互斥)
  8. 新概念51单片机C语言教程纠错(2)
  9. c++报错:引用了未定义标签_大牛带你解读Spring源码,编写自定义标签,您能学会吗?...
  10. python configure函数 循环_使用python统计git仓库中频繁修改的热点函数