c++文件操作,超详细

简介: c++文件操作,超详细

包含头文件:#include <fstream> 三种流的使用都需要包含该头文件

类:ofstream(写)ifstream(读) fstream(读写)

类:ofstream:

ofstream的构造函数

ofstream fout();
//filename的类型是char *或者string都可以
ofstream fout(filename);
ofstream fout(filename, ios::out);
ofstream fout(filename, ios::trunc);
ofstream fout(filename, ios::app);

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

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

ios::out 缺省值:会截断文件内容。(即清空文件)

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

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

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

以文本模式写入文件

文本文件一般以行的形式组织数据。

代码示例
#include <iostream>
#include <fstream>  // ofstream类需要包含的头文件。
using  namespace std;
int main()
{
  /*
      文件名一般用全路径,几种书写方式:
      1."D:\data\txt\test.txt"      // 错误。
      2.R"(D:\data\txt\test.txt)"   // 原始字面量,C++11标准。
      3."D:\\data\\txt\\test.txt"   // 转义字符。
      4."D:/tata/txt/test.txt"      // 把斜线反着写。
      5."/data/txt/test.txt"        //  Linux系统采用的方法。
  */
  //string filename = R"(D:\data\txt\test.txt)"; //建议c++11吧,我这里注释了
  string filename = "D:/VS_project/CPP_base/pretreatment_namespace/demo.txt";
  ofstream fout;
  fout.open(filename, ios::out);
  // 判断打开文件是否成功。
  // 失败的原因主要有:1。目录不存在;2。磁盘空间已满;3。没有权限,Linux平台下很常见。
  if (fout.is_open() == false)
  {
    cout << "打开文件" << filename << "失败。\n";  return 0;
  }
  // 向文件中写入数据。
  fout << "熊大光头强又来砍树了\n";
  fout.close();    // 关闭文件,fout对象失效前会自动调用close()。
  cout << "操作文件完成。\n";
}

写入二进制文件

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

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

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

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

3)在windows平台下,如果以文本方式打开文件,写入数据的时候,系统会将"\n"转换成"\r\n";读取数据的时候,系统会将"\r\n"转换成"\n"。 如果以二进制方式打开文件,写和读都不会进行转换。

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

5)以文本方式读取文件的时候,遇到换行符停止,读入的内容中没有换行符;以二制方式读取文件的时候,遇到换行符不会停止,读入的内容中会包含换行符(换行符被视为数据)。

6)在实际开发中,从兼容和语义考虑,一般:a)以文本模式打开文本文件,用行的方法操作它;b)以二进制模式打开二进制文件,用数据块的方法操作它;c)以二进制模式打开文本文件和二进制文件,用数据块的方法操作它,这种情况表示不关心数据的内容。(例如复制文件和传输文件)d)不要以文本模式打开二进制文件,也不要用行的方法操作二进制文件,可能会破坏二进制数据文件的格式,也没有必要。(因为二进制文件中的某字节的取值可能是换行符,但它的意义并不是换行,可能是整数n个字节中的某个字节)

注意了:

不同文件有不同的格式,比如说,图片,mp4,都有自己的二进制格式,你把他们写入相应的文件中,自然不会出错,但是你把他们写入文本文件中,肯定会乱码,这都很好理解是吧。

如果我们自己定义了一个结构体,这个结构体就是我们程序员自己搞的一个文件格式,如果你把他写入文本文件中一样会乱码,因为他不知道我们是怎么规定的,他没有办法去解码。

示例:
#include <iostream>
#include <fstream>
using namespace std;
// 自定义的格式
struct student
{
    int age = 10;
    string name = "小名"; // 修正成员变量名
};
int main()
{
    string filename = "D:\\VS_project\\CPP_base\\pretreatment_namespace\\demo.txt"; // 修正文件名
    ofstream f;
    f.open(filename, ios::out | ios::binary);
    // 检查文件是否成功打开
    if (f.is_open())
        cout << "打开文件成功" << endl;
    else
    {
        cout << "打开文件失败" << endl;
        return 1; // 如果打开失败,结束程序
    }
    student s;
    f.write(reinterpret_cast<char*>(&s), sizeof(s)); // 使用reinterpret_cast进行类型转换
    return 0;
}

必然是乱码,自己试试吧

类:ifstream

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

ios::in 缺省值。(即不传默认ios::in模式)

ifstream打开文本文件:

代码示例:
#include <iostream>
#include <fstream>  // ifstream类需要包含的头文件。
#include <string>     // getline()函数需要包含的头文件。
using  namespace std;
int main()
{
  string filename = R"(D:\VS_project\CPP_base\pretreatment_namespace\demo.txt)";
  ifstream fin;
  fin.open(filename, ios::in);
  if (fin.is_open() == false)
  {
    cout << "打开文件" << filename << "失败。\n";  return 0;
  }
  // 第一种方法。
  //string buffer; 
   全局函数getline(采用的流对象,存储对象)一次读一行直到读完
  //while (getline(fin, buffer))
  //{
  //  cout << buffer << endl;
  //}
   第二种方法。
  //char buffer[60];   //一定要保证缓冲区足够大如果不够大将不打印
  //while (fin.getline(buffer, 59))
  //{
  //  cout << buffer << endl;
  //}
   //第三种方法。
  string buffer;
  while (fin >> buffer)
  {
    cout << buffer << endl;
  }
  fin.close();     
  cout << "操作文件完成。\n";
}

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

类:ifstream

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

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

示例:

前面我们写了一个结构体,然后将他写文本文件,文本文件,不知道如果解析他,但那时我们自己知道

#include <iostream>
#include <fstream>
using namespace std;
// 自定义的格式
struct student
{
    int age = 10;
    string name = "小名"; // 修正成员变量名
};
int main()
{
    string filename = "D:\\VS_project\\CPP_base\\pretreatment_namespace\\demo.txt"; // 修正文件名
    istream f;
    f.open(filename, ios::out | ios::binary);
    // 检查文件是否成功打开
    if (f.is_open())
        cout << "打开文件成功" << endl;
    else
    {
        cout << "打开文件失败" << endl;
        return 1; // 如果打开失败,结束程序
    }
    student s;
    f.write(reinterpret_cast<char*>(&s), sizeof s); // 使用reinterpret_cast进行类型转换
    f.seekg(ios::beg);
    f.read(reinterpret_cast<char*>(&s), sizeof s);
    cout << s.name << s.age << endl;
    return 0;
}
输出:

类:fstream类

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

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

那么我们怎么选择呢:

1.如果只想写入数据,用ofstream;如果只想读取数据,用ifstream;如果想写和读数据,用fstream,这种情况不多见。不同的类体现不同的语义。

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

有写文件只有读的操作,但是你写以fstream可能就会打开文件失败

具体操作和ofstream,ifstream没有什么太大区别这里就不做赘述了

文件位置指针

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

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

1.获取文件位置指针

ofstream类的成员函数是tellp();

ifstream类的成员函数是tellg();

fstream类两个都有,效果相同。没区别

2.移动文件位置指针

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

方法一:

istream & seekg(std::streampos _Pos);  
fin.seekg(128);   // 把文件指针移到第128字节。
fin.seekp(128);   // 把文件指针移到第128字节。
fin.seekg(ios::beg) // 把文件指针移动文件的开始。
fin.seekp(ios::end) // 把文件指针移动文件的结尾。

方法二:

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

在ios中定义的枚举类型:

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>  // ofstream类需要包含的头文件。
#include <cstring>
using  namespace std;
int main()
{
  string filename = R"(D:\VS_project\CPP_base\pretreatment_namespace\demo.txt)";
  fstream f;
  f.open(filename);
  string buffer = "熊大熊二\n";
  int cnt = 2;
  if (f.is_open())
  {
    cout << "文件打开成功" << endl;
    cout << "文件指针的位置" << f.tellp() << endl;
    while (cnt--)
    {
      f << buffer;
      cout << "文件位置指针" << f.tellp() << endl;
    }
  }
  cout << "写完之后文件位置指针" << f.tellp() << endl;
  cnt = 2;
    /*注意一定要重定位文件指针的位置,要不然写完之后文件指针指向文件末尾,
    再次读文从文件末尾开始读是读不出数据的,这里也再次应正文件指针就一个,
    只不过写了两个函数,区分一下语义*/
  f.seekg(ios::beg);
  while (cnt--)
  {
    f >> buffer;
    cout << buffer << endl;
    cout << "文件位置指针" << f.tellg() << endl;
  }
  cout << "操作文件完成。\n";
}

输出:

注意:

ios::out      //会截断文件,可以用seekp()移动文件指针。
ios:trunc     //会截断文件,可以用seekp()移动文件指针。
ios::app      //不会截断文件,文件指针始终在文件未尾,不能用seekp()移动文件指针。
ios::ate      //打开文件时文件指针指向文件末尾,但是,可以在文件中的任何地方写数据。

文件缓冲区

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

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

注意,在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()成员函数重置流状态。

注:

本文部分采用慕课网c++基础课教程,如有侵权立即删除

目录
相关文章
|
6月前
|
安全 算法 程序员
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
【C/C++ 文件操作】深入理解C语言中的文件锁定机制
201 0
|
6月前
|
存储 C++ iOS开发
C++文件操作
C++文件操作
|
6月前
|
C++ iOS开发
C++ 文件操作的技术性文章
C++ 文件操作的技术性文章
31 0
|
5月前
|
存储 C++
C++文件操作
C++文件操作
|
6月前
|
存储 C语言 数据安全/隐私保护
C++中的文件操作技术详解
C++中的文件操作技术详解
|
6月前
|
C++
C++语言学习文件操作应用案例
C++文件操作示例:创建`ofstream`对象写入&quot;Hello, World!&quot;到`output.txt`,刷新缓冲区,然后使用`ifstream`读取并打印文件内容。如果文件打开失败,程序将显示错误信息并返回1。
36 3
|
6月前
|
存储 编译器 程序员
【C++ 文件操作与字符串处理】从文件读取到内容分割的全方位指南
【C++ 文件操作与字符串处理】从文件读取到内容分割的全方位指南
603 6
|
6月前
|
C++
深入理解 C++ 中的多态与文件操作
C++中的多态是OOP核心概念,通过继承和虚函数实现。虚函数允许对象在相同操作下表现不同行为,提高代码可重用性、灵活性和可维护性。例如,基类`Animal`声明`makeSound()`虚函数,派生类如`Cat`、`Dog`和`Bird`可重写该函数实现各自叫声。C++也提供多种文件操作,如`fstream`库的`ofstream`、`ifstream`用于读写文件,C++17引入的`&lt;filesystem&gt;`库提供更现代的文件操作接口。
56 0
|
6月前
|
存储 C++
C++从入门到精通:2.3.1文件操作
C++从入门到精通:2.3.1文件操作