C++017-C++文件读写应用

简介: C++017-C++文件读写应用

C++017-C++文件读写应用



在线练习:

http://noi.openjudge.cn/

https://www.luogu.com.cn/


C++文件读写应用


参考:

中文编码杂谈

https://space.bilibili.com/627875426

C++文件读写详解(ofstream,ifstream,fstream)


494aaad51b83eacfa20fb3938dc66664_26f5b8ad45334e7581e77b97ff0ebb41.png


CSP-J目标

· 【 2 】文件的基本概念、文本文件的基本操作

· 【 2 】文本文件类型与二进制文件类型

· 【 2 】文件重定向、文件读写等操作


1. 文件的基本概念、文本文件的基本操作

在C++中,文件是一种数据存储方式,它可以是文本文件或二进制文件。文本文件是以文本格式存储数据的文件,每个字符都被存储为其ASCII码值的文本文件,可以用普通的文本编辑器打开和编辑。在C++中,可以使用标准库中的文件流来打开、读取、写入和关闭文件。


打开文件:使用文件流对象(例如 ifstream 或 ofstream)创建一个文件对象并打开文件。打开文件时,可以指定打开模式,例如只读、只写、追加等模式。

读取文件:使用输入流对象(例如 ifstream)从文件中读取数据。可以使用不同的读取函数,例如 getline、get、read等。要读取文件,必须先打开文件。

写入文件:使用输出流对象(例如 ofstream)向文件中写入数据。可以使用不同的写入函数,例如 put、write、<< 运算符等。要写入文件,必须先打开文件。

关闭文件:使用文件流对象的 close() 函数关闭文件。关闭文件后,不能再对其进行读取或写入操作。

494aaad51b83eacfa20fb3938dc66664_26f5b8ad45334e7581e77b97ff0ebb41.png


#include <fstream>  
ofstream         //文件写操作 内存写入存储设备 (由ostream引申而来)   
ifstream         //文件读操作,存储设备读区到内存中  (由ostream引申而来) 
fstream          //读写操作,对打开的文件可进行读写操作  (由iostream引申而来) 

2.文本文件类型与二进制文件类型

参考:https://www.cnblogs.com/xkfz007/archive/2011/07/21/2176994.html



5782b81d3b8ab72f066fffd71fadf5cd.jpge0935cb12e5e4578a163382f3a666229.png

f2d8337e3e332d89f4b25a18cd7d8e64.jpg


文本文件类型

txt是纯文本格式,简单来说就是没有格式的普通文本文件;csv是逗号分隔值文件,用逗号分隔数据字段;json是一种轻量级的数据交换格式,以键值对的形式存储数据;xml是可扩展标记语言,用于存储和传输数据;html是超文本标记语言,用于创建网页和其他可视化浏览器界面的文件格式。


二进制文件类型

二进制文件类型有很多种,其中常见的有以下几种:

可执行文件:一般是以.exe为后缀名的文件,可以直接运行。

动态链接库(DLL):一般是以.dll为后缀名的文件,它是一种动态链接库文件,包含一些被程序调用的函数和数据。

静态链接库(LIB):一般是以.lib为后缀名的文件,它也是一种库文件,但是不同于DLL文件,它在编译时被链接到程序中。

数据文件:一般是以.dat、.bin等后缀名的文件,里面存放着程序需要的数据。

图像文件:一般是以.bmp、.jpg、.png等后缀名的文件,存储着图像的二进制数据。

音频文件:一般是以.mp3、.wav等后缀名的文件,存储着音频的二进制数据。

举例说明,例如.exe文件就是一种二进制文件,它可以直接执行,例如:游戏中的游戏客户端。DLL文件则是一种动态链接库,例如:Windows系统中的一些系统DLL文件。LIB文件则是一种静态链接库文件,例如:开发中使用的一些通用库。而图像文件、音频文件等等,它们都是二进制数据的存储方式。


二进制查看工具

一个文件,内容如下:


ABCD

abcd


用Binary Viewer打开

a4c2d2eca1defeff06191300f25abcf7_a8dc67f44c7444098866eea16bd2c8fa.png


Hexadecimal是字节流内容,右侧是字符流内容。Hexadecimal中的内容形式是十六进制数,因为字符在操作系统中存储的形式是ASCII码值,所以左侧红框里的数值是的十六进制形式的ASCII码值,右侧是该ASCII码值对应的字符内容。。比如左侧第一个十六进制数字是41,其对应的十进制是4*16 + 1=65,在ASCII码表中65对应的是A,如上图右侧框中的第一个字母所示。下方给出ASCII码表。

625dff1b7a777a0f5f721464df5c6de1_3e558e2f83a046e0b709c8629dc4faf4.png


3.文件重定向、文件读写等操作

关闭文件

当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。成员函数close(),它负责将缓存中的数据排放出来并关闭文件。这个函数一旦被调用,原先的流对象就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程所访问了。为防止流对象被销毁时还联系着打开的文件,析构函数将会自动调用关闭函数close。


文件操作-写入文本文件

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

在fstream类中,成员函数open()实现打开文件的操作,从而将数据流和文件进行关联,通过ofstream,ifstream,fstream对象进行对文件的读写操作


函数:open()


public member function
void open ( const char * filename,
            ios_base::openmode mode = ios_base::in | ios_base::out );
void open(const wchar_t *_Filename,
        ios_base::openmode mode= ios_base::in | ios_base::out,
        int prot = ios_base::_Openprot);

打开文件的方式在ios类(所以流式I/O的基类)中定义,有如下几种方式:

01d9e3d4dfe45ec45b10faba6550c6c2_67dab01bc5cb473ca21d673fbcf7e1e1.png


包含头文件:#include <fstream>
类:ofstream(output file stream)

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

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

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

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

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


示例:


#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)";
  //char    filename[] = R"(D:\data\txt\test.txt)";
  // 创建文件输出流对象,打开文件,如果文件不存在,则创建它。
  // ios::out         缺省值:会截断文件内容。
  // ios::trunc     截断文件内容。(truncate)
  // ios::app         不截断文件内容,只在文件未尾追加文件。(append)
  //ofstream fout(filename);
  //ofstream fout(filename, ios::out);
  //ofstream fout(filename, ios::trunc);
  //ofstream fout(filename, ios::app);
  ofstream fout;
  fout.open(filename,ios::app);
  // 判断打开文件是否成功。
  // 失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
  if (fout.is_open() == false)
  {
    cout << "打开文件" << filename << "失败。\n";  return 0;
  }
  // 向文件中写入数据。
  fout << "你好 淄博1\n";
  fout << "你好 淄博2\n";
  fout << "你好 淄博3\n";
  fout.close();    // 关闭文件,fout对象失效前会自动调用close()。
  cout << "操作文件完成。\n";
}

文件操作-读取文本文件

包含头文件:#include <fstream>
类:ifstream

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

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

ios::in 缺省值。


示例:


#include <iostream>
#include <fstream>  // ifstream类需要包含的头文件。
#include <string>     // getline()函数需要包含的头文件。
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)";
  //char    filename[] = R"(D:\data\txt\test.txt)";
  // 创建文件输入流对象,打开文件,如果文件不存在,则打开文件失败。。
  // ios::in          缺省值。
  //ifstream fin(filename);
  //ifstream fin(filename, ios::in);
  ifstream fin;
  fin.open(filename,ios::in);
  // 判断打开文件是否成功。
  // 失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux平台下很常见。
  if (fin.is_open() == false)
  {
    cout << "打开文件" << filename << "失败。\n";  return 0;
  }
   第一种方法。
  //string buffer;  // 用于存放从文件中读取的内容。
   文本文件一般以行的方式组织数据。
  //while (getline(fin, buffer))
  //{
  //  cout << buffer << endl;
  //}
   第二种方法。
  //char buffer[16];   // 存放从文件中读取的内容。
   注意:如果采用ifstream.getline(),一定要保证缓冲区足够大。
  //while (fin.getline(buffer, 15))
  //{
  //  cout << buffer << endl;
  //}
  // 第三种方法。
  string buffer;
  // 析取器(>>),>>遇到空格、换行符后停止读取文件,待再次调用时才接着读取。可以理解为>>不读空格、换行符
  while (fin >> buffer)
  {
    cout << buffer << endl;
  }
  fin.close();     // 关闭文件,fin对象失效前会自动调用close()。
  cout << "操作文件完成。\n";
}

fe6ba47139ed5431464eb6ac51f644b1_e33b8656d0fc433f9591c7dac7a9378e.png


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

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


包含头文件:#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"(.\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;         // 体重。
  };
  struct st_girl girl = { "西施",3,"中国历史第一美女。" ,45.8 };
  fout.write((const char *)& girl, sizeof(st_girl));   // 写入第一块数据。
  struct st_girl girl2 = { "冰冰",8,"也是个大美女哦。",55.2};
  fout.write((const char*)&girl2, sizeof(st_girl));     // 写入第二块数据。
  fout.close();    // 关闭文件,fout对象失效前会自动调用close()。
  cout << "操作文件完成。\n";
}

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

包含头文件:#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"(.\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";
}

d77adad54203508bde8ec305d5c6980e_578ef92695b74a41b0e801e67ab9cfeb.png


文件操作-随机存取

一、fstream类

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

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

普遍的做法是:

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

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";
}

55244a4894774b6581e8b2e18bd6d01c_95d49dcbb1234fd8a16a54dc4745612d.png


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

一、写文件

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


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(追加)的缩写。


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

一、文件缓冲区

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

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

注意,在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<windows.h> //window下的Sleep
//#include <unistd.h> // linux下的 usleep(100000)
using  namespace std;
int main()
{
  ofstream fout("./bbb.txt");   // 打开文件。
  fout << unitbuf;
  for (int ii = 0; ii < 100; ii++)  // 循环1000次。
  {
    fout << "ii=" << ii << ",我是一只傻傻傻傻傻傻傻傻傻傻傻傻傻傻的鸟。\n";
    //fout.flush();      // 刷新缓冲区。
    //usleep(100000);    // 睡眠十分之一秒 linux下。
    Sleep(1);
  }
  fout.close();  // 关闭文件。
}

53f97d2c23e34884536165506497faca_733f682901a9499baf61adb3a4ca0a54.png


示例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()。
}

354923d6a5936ef9dead456be3b79483_e64d86cfa7564b76bd812ac65ad616a7.png


C++ 文件重定向

<一>、简单的理解重定向:


就是:


把 原来的 cin 从键盘输入 改为从文件输入。

把 原来的 cout 向屏幕输出 改为输出到文件。

例如: cin>>line; 原来要从键盘拍入。现在自动到某文件读取,语句还是 cin>>line; 不变。

cout << line << endl; 原来向屏幕输出,现在自动写到某文件里,语句还是cout << line << endl;不变

=======


C++ 实现方法:

rdbuf() 函数定义在<ios>头文件中,专门用于实现 C++ 输入输出流的重定向。


值得一提的是,ios 作为 istream 和 ostream 类的基类,rdbuf() 函数也被继承,因此 cin 和 cout 可以直接调用该函数实现重定向.

rdbuf() 函数的语法格式有 2 种,分别为:


streambuf * rdbuf() const;
streambuf * rdbuf(streambuf * sb);

streambuf 是 C++ 标准库中用于表示缓冲区的类,该类的指针对象用于代指某个具体的流缓冲区。

其中,第一种语法格式仅是返回一个指向当前流缓冲区的指针;第二种语法格式用于将 sb 指向的缓冲区设置为当前流的新缓冲区,并返回一个指向旧缓冲区的对象。


案例1:


#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    //打开 in.txt 文件,等待读取
    ifstream fin("test.txt");
    //打开 out.txt 文件,等待写入
    ofstream fout("out.txt");
    streambuf *oldcin;
    streambuf *oldcout;
    char a[100];
    //用 rdbuf() 重新定向,返回旧输入流缓冲区指针
    oldcin = cin.rdbuf(fin.rdbuf());
    //用 rdbuf() 重新定向,返回旧输出流缓冲区指针
    oldcout = cout.rdbuf(fout.rdbuf());
    //从input.txt文件读入
    while (cin >> a){
        //写入 out.txt
        cout << a << endl;
    }
    //还原标准输入输出流
    cin.rdbuf(oldcin); // 恢复键盘输入
    cout.rdbuf(oldcout); //恢复屏幕输出
    //打开的文件,最终需要手动关闭
    fin.close();
    fout.close();
    return 0;

案例2:


#include <iostream>
#include <ostream>
#include <fstream>
using namespace std;
main()
{
ifstream fin("./test.txt"); // 已有输入文件
ofstream fout("./output.txt"); //输出文件
streambuf *cinbackup;
streambuf *coutbackup;
coutbackup= cout.rdbuf(fout.rdbuf()); //用 rdbuf() 重新定向
cinbackup= cin.rdbuf(fin.rdbuf()); //用 rdbuf() 重新定向
cout<<"Hello world"<<endl; //去文件也
char line[100];
while (cin>>line){ //从input.txt文件读入
    cout<<line<<endl; //写入 output.txt
};
// restore standard streambuf
cin.rdbuf(cinbackup); // 取消,恢复键盘输入
cout.rdbuf(coutbackup); //取消,恢复屏幕输出
return 0;
}

51c67df9d299723f88e5eaee5764aa29_33fd4fb2d2c3425b8f39c7510c4f868b.png


C++基于控制台实现重定向

C++通过控制台实现重定向

以上 2 种方法,都是从代码层面实现输入输出流的重定向。除此之外,我们还可以通过控制台实现输入输出的重定向。


#include <iostream>
#include <string>
using namespace std;
int main()
{
    string name, url;
    cin >> name >> url;
    cout << name << '\n' << url;
    return 0;
}

编译运行后,在debug目录下生成

D:\cplusproject\day0305\bin\Debug\day0305.exe


在D:\cplusproject\day0305\bin\Debug中创建a.txt


你好啊

啊阿达fd

dfdf

12


运行:

day0305.exe <a.txt >b.txt

生成b.txt


你好啊

啊阿达fd


C语言freopen()函数实现重定向

freopen() 定义在<stdio.h>头文件中,是 C 语言标准库中的函数,专门用于重定向输入流(包括 scanf()、gets() 等)和输出流(包括 printf()、puts() 等)。值得一提的是,该函数也可以对 C++ 中的 cin 和 cout 进行重定向。

#include <iostream>    //cin、cout
#include <string>      //string
#include <stdio.h>     //freopen
using namespace std;
int main()
{
    string name, url;
    //将标准输入流重定向到 in.txt 文件
    freopen("test.txt", "r", stdin);
    cin >> name >> url;
    //将标准输出重定向到 out.txt文件
    freopen("out.txt", "w", stdout);
    cout << name << "\n" << url;
    return 0;
}

d5d8beb1ac122c964973536395f2ce06_811bef1c6be845d4be6c42a2c9ec3620.png


2.文件读写操作

基本案例

#include <iostream>
#include <fstream>
using namespace std;
int main() {
    // 打开文件
    ofstream outfile("data.txt");
    if (!outfile.is_open()) {
        cout << "无法打开文件" << endl;
        return 1;
    }
    // 写入数据
    outfile << "Hello, world!" << endl;
    outfile << "Hello, world222" << endl;
    // 关闭文件
    outfile.close();
    // 重新打开文件
    ifstream infile("data.txt");
    if (!infile.is_open()) {
        cout << "无法打开文件" << endl;
        return 1;
    }
    // 读取数据
    string line;
//    getline(infile, line);
//    cout << line << endl;
    while (getline(infile,line))
    {
        cout<<line<<endl;
    }
    // 关闭文件
    infile.close();
    return 0;
}

0efba5ddfe8ee6dbf73658d0cde1cd21_cc7fce59e975485496527c1db3f704f6.png


seekg() 和 tellg() 函数来读取文件中的数据

判断文件是否打开:可以使用文件流对象的 is_open() 函数来判断文件是否成功打开。如果打开成功,该函数将返回 true,否则返回 false。

获取文件位置:可以使用输入流对象的 tellg() 函数获取当前的读取位置,使用输出流对象的 tellp() 函数获取当前的写入位置。这些函数返回的值是一个指针,指向当前位置的字节偏移量。

移动文件位置:可以使用输入流对象的 seekg() 函数和输出流对象的 seekp() 函数移动读取或写入位置。这些函数的第一个参数是一个指针,指定要移动的位置的字节偏移量,第二个参数指定相对于哪个位置进行移动,例如 ios::beg(文件开头)、ios::cur(当前位置)或 ios::end(文件末尾)。

判断文件结束:可以使用输入流对象的 eof() 函数判断是否已经到达文件末尾。如果已经到达文件末尾,该函数将返回 true,否则返回 false。


#include <iostream>
#include <fstream>
using namespace std;
int main() {
        // 打开文件
    ofstream outfile("data.txt");
    if (!outfile.is_open()) {
        cout << "无法打开文件" << endl;
        return 1;
    }
    // 写入数据
    //outfile << "Hello, world!" << endl;
    outfile << "Hello, world!1" << endl;
    outfile << "Hello, world!1"<<endl;
    // 关闭文件
    outfile.close();
    // 打开文件
    ifstream infile("data.txt");
    if (!infile.is_open()) {
        cout << "无法打开文件" << endl;
        return 1;
    }
    // 获取文件大小
    infile.seekg(0, ios::end);
    int length = infile.tellg();
    infile.seekg(0, ios::beg);
    cout<<"长度为:"<<length<<endl;
    // 读取数据
    char* buffer = new char[length+1];
    cout<<"buffer长度为:"<<sizeof(buffer)<<endl;
    infile.read(buffer, length);
    buffer[length] = '\0';
    // 输出数据
    cout << buffer << endl;
    // 释放内存并关闭文件
    delete[] buffer;
    infile.close();
    return 0;
}

image.png


在线练习:


http://noi.openjudge.cn/


总结


本系列为C++学习系列,会介绍C++基础语法,基础算法与数据结构的相关内容。本文为C++文件读写应用案例,包括相关案例练习。

相关文章
|
2月前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
6月前
|
存储 安全 C++
C++中的引用和指针:区别与应用
引用和指针在C++中都有其独特的优势和应用场景。引用更适合简洁、安全的代码,而指针提供了更大的灵活性和动态内存管理的能力。在实际编程中,根据需求选择适当的类型,能够编写出高效、可维护的代码。理解并正确使用这两种类型,是掌握C++编程的关键一步。
79 1
|
7月前
|
C++
C++中的封装、继承与多态:深入理解与应用
C++中的封装、继承与多态:深入理解与应用
166 1
|
2月前
|
存储 编译器 C++
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
【C++篇】揭开 C++ STL list 容器的神秘面纱:从底层设计到高效应用的全景解析(附源码)
59 2
|
3月前
|
编译器 C++
【C++核心】函数的应用和提高详解
这篇文章详细讲解了C++函数的定义、调用、值传递、常见样式、声明、分文件编写以及函数提高的内容,包括函数默认参数、占位参数、重载等高级用法。
26 3
|
4月前
|
存储 算法 C++
C++ STL应用宝典:高效处理数据的艺术与实战技巧大揭秘!
【8月更文挑战第22天】C++ STL(标准模板库)是一组高效的数据结构与算法集合,极大提升编程效率与代码可读性。它包括容器、迭代器、算法等组件。例如,统计文本中单词频率可用`std::map`和`std::ifstream`实现;对数据排序及找极值则可通过`std::vector`结合`std::sort`、`std::min/max_element`完成;而快速查找字符串则适合使用`std::set`配合其内置的`find`方法。这些示例展示了STL的强大功能,有助于编写简洁高效的代码。
52 2
|
4月前
|
存储 搜索推荐 Serverless
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
【C++航海王:追寻罗杰的编程之路】哈希的应用——位图 | 布隆过滤器
38 1
|
4月前
|
JSON Android开发 C++
Android c++ core guideline checker 应用
Android c++ core guideline checker 应用
|
6月前
|
关系型数据库 MySQL 测试技术
技术分享:深入C++时间操作函数的应用与实践
技术分享:深入C++时间操作函数的应用与实践
55 1