• [C++]文件读写操作


    步骤1:包含头文件 #include < fstream >

    步骤2:创建流对象

    包括:1)ofstream : 写文件 (2)ifstream : 读文件 (3)fsream : 读写文件

    如:

    1. ifstream fin;
    2. ofstream fout;

    步骤3:打开文件

    打开文件 fin.open ("文件路径" ,打开方式)

    打开方式包括:

    1. ios::in 读文件
    2. ios::out 写文件(直接用的话会丢丢弃已有数据,即隐含为trunc)
    3. ios::binary 二进制方式
    4. ios:app 追加写(要配合out使用,直接写的话会隐含用ios::out
    5. ios::trunc 覆盖写(要配合out使用)
    6. ios::out|ios::binary 二进制写
    7. ……

    如:

    fin.open("/home/bing/slambook14/slambook/ch2/test1.txt",ios::in);

    步骤4:读写数据

    步骤4-1:向流中写入数据,最后关闭流

    1. fout << x << " " << y << endl;
    2. fout.close();

    步骤4-2:从流中读取数据

    为了保持健壮性,读文件要有验证代码:

    1. if(!fin.is_open())
    2. {
    3. std::cerr<<"cannot open the file"
    4. }
    5. //或者
    6. if(!fin)
    7. {
    8. std::cerr<<"cannot open the file";
    9. }

    第一种读的方式(按元素直接读):

    1. //申请读空间:
    2. char buf[1024]={0}; 就是临时申请一个 1024大的读空间(又叫buffer),并且初始化为0
    3. while (fin >> buf)
    4. {
    5. cout << buf << endl;//每一次的buf是空格或回车键(即白色字符)分开的元素
    6. }
    7. 文件:
    8. 1 2 3
    9. a b c
    10. 112
    11. geya
    12. 读取结果:
    13. 1
    14. 2
    15. 3
    16. a
    17. b
    18. c
    19. 112
    20. geya

    第二种读的方式(使用getline按行读):

    默认读取数据时,它会传递并忽略任何白色字符(空格、制表符或换行符)。一旦它接触到第一个非空格字符即开始阅读,当它读取到下一个空白字符时,它将停止读取。

    为了解决这个问题,可以使用一个叫做 getline 的 C++ 函数。此函数可读取整行白色字符,只看换行符,即不看,包括前导和嵌入的空格,并将其存储在字符串对象中。

    getline:

    getline()函数是istream类中的一个成员函数,所以在使用它时,速妖使用istream的对象cin来调用它。getline (char* s, streamsize n ),作用是从istream中读取至多n个字符保存在s对应的数组中。即使还没读够n个字符,如果遇到换行符'\n'则读取终止

    1. char buf[1021]={0};
    2. while(fin.getline(buf,sizeof(buf)))
    3. {
    4. std::cout<<buf<<std::endl;
    5. }
    6. 文件:
    7. 1 2 3
    8. a b c
    9. 112
    10. geya
    11. 读取结果:
    12. 1 2 3
    13. a b c
    14. 112
    15. geya

    第三种读的方式(get):

    1. char c;
    2. while ((c = fin.get()) != EOF)
    3. {
    4. std::cout << c;
    5. }
    6. 文件:
    7. 1 2 3
    8. a b c
    9. 112
    10. geya
    11. 读取结果:
    12. 1 2 3
    13. a b c
    14. 112
    15. geya

    第四种读的方式:

    若已知文件里头数据的顺序,则直接定义字符变量存储单个元素,以白色字符为分割

    1. char a,s1,s2,s3,s4,s5;
    2. std::string s6;
    3. fin >> a >> s1 >> s2 >> s3>>s4>>s5>>s6;
    4. std::cout<<a<<" "<<s1<<" "<<s2<<" "<<s3<<" "<<s4<<" "<<s5<<" "<<s6;
    5. 文件:
    6. 1 2 3
    7. a b c
    8. 112
    9. geya
    10. 读取结果:
    11. 1 2 3 a b c 112

    步骤5:数据类型转换

    一般默认从文件中读取的是字符格式或者字符串格式的数据,如果是数字要转化为float等格式怎么办呢?

    方法一:直接定义负责接受的变量数据类型,按行分后再按单词分

    下面这个例子就是实际应用中经常用到的例子,比如一个人有多个手机号:

    一行代表一个人的信息,以行为单位存储信息:

    1. #include "libHelloSLAM.h"
    2. #include<iostream>
    3. #include<fstream>
    4. #include<string>
    5. #include<vector>
    6. #include <sstream>
    7. struct people{
    8. std::string name;
    9. std::vector<int> phonenum;
    10. };
    11. int main( int argc, char** argv )
    12. {
    13. std::ifstream fin;
    14. fin.open("/home/bing/slambook14/slambook/ch2/test.txt",std::ios::in);
    15. if(!fin.is_open())
    16. {
    17. std::cerr<<"cannot open the file";
    18. }
    19. char line[1024]={0};
    20. std::vector<people> People;
    21. //从文件中提取“行”
    22. while(fin.getline(line,sizeof(line)))
    23. {
    24. //定义局部变量
    25. people p;
    26. //从“行”中提取“单词”
    27. std::stringstream word(line);
    28. word>>p.name ;
    29. int num;
    30. while(word>>num)
    31. p.phonenum.push_back(num);
    32. People.push_back(p);
    33. }
    34. std::cout<<People[1].name<<"'s phonenumber is:"<< People[1].phonenum[1];
    35. }
    36. 文件:
    37. gyb 1333 12212
    38. lck 212 33113
    39. ddl 332 41311
    40. 输出:
    41. lck's phonenumber is:33113

    反正最重要的是以下两个:

    //从文件中提取“行”

    fin.getline(line,sizeof(line))

    //从“行”中提取“单词”
    std::stringstream word(line);

    这里用到了stringstream,需要包含 主要用来进行数据类型转换

    如:

    1. #include <string>
    2. #include <sstream>
    3. #include <iostream>
    4. #include <stdio.h>
    5. using namespace std;
    6. int main()
    7. {
    8. stringstream sstream;
    9. string strResult;
    10. int nValue = 1000;
    11. // 将int类型的值放入输入流中
    12. sstream << nValue;
    13. // 从sstream中抽取前面插入的int类型的值,赋给string类型
    14. sstream >> strResult;
    15. cout << "[cout]strResult is: " << strResult << endl;
    16. printf("[printf]strResult is: %s\n", strResult.c_str());
    17. //这里的 str() 方法是将 stringstream 类型转换为 string 类型
    18. return 0;
    19. }

    其他:

    1、stringstream其实和ostringstream一样可以看错一个内存,起到暂时存储的作用 其实还有个tringsteam可以读写,待深入研究;

    2、一般流的读写用<< 和>> ,而不用=

    如读:word>>p.name ;把word中的东西读到p.name中

    写:cin>>word

    3、读写操作可以作为条件使用,若没东西可以读写了,则返回-1

    如:

    while(word>>num){}

    **********************************************************************

    补充看到的orbslam中的读取文件的代码

    1. void LoadImages(const string &strPathToSequence, vector<string> &vstrImageFilenames, vector<double> &vTimestamps)
    2. {
    3. // step 1 读取时间戳文件
    4. ifstream fTimes;
    5. string strPathTimeFile = strPathToSequence + "/times.txt";
    6. fTimes.open(strPathTimeFile.c_str());
    7. while(!fTimes.eof())
    8. {
    9. string s;
    10. getline(fTimes,s);
    11. // 当该行不为空的时候执行
    12. if(!s.empty())
    13. {
    14. stringstream ss;
    15. ss << s;
    16. double t;
    17. ss >> t;
    18. // 保存时间戳
    19. vTimestamps.push_back(t);
    20. }
    21. string strPrefixLeft = strPathToSequence + "/image_0/";
    22. const int nTimes = vTimestamps.size();
    23. vstrImageFilenames.resize(nTimes);
    24. for(int i=0; i<nTimes; i++)
    25. {
    26. stringstream ss;
    27. ss << setfill('0') << setw(6) << i;
    28. vstrImageFilenames[i] = strPrefixLeft + ss.str() + ".png";
    29. }

    **********************************************************************

    最好把文件名用全局变量定义出来

    string filename=“./test.txt"

    **********************************************************************

    1. //多文件,按文件名顺序读写
    2. //使用boost::format进行字符串的格式化
    3. boost::format fmt("./%s/%d.%s");
    4. for(int i =0 ;i<5;i++)
    5. cv::imread((fmt%"color"%(i+1)%"png").str())

    *****************************************************************************

    读特定列:

    1. int main()
    2. {
    3. ifstream ff1;
    4. ff1.open("/home/bing/ORB/ORB_SLAM2/LiGT/LiGT_results.txt");
    5. char line[1024] = {0};
    6. if(!ff1.is_open()) cerr<<"can not open";
    7. float globalt[1000][3];
    8. int ii=0;
    9. while(ff1.getline(line,sizeof(line)))
    10. {
    11. std::stringstream word(line);
    12. for(int qq=0;qq<12;qq++)
    13. {
    14. float tamp;
    15. word>>tamp;
    16. // cout<< tamp<< " "<<qq<<endl;
    17. if (qq == 9) globalt[ii][0] = tamp;
    18. if (qq == 10)globalt[ii][1] = tamp;
    19. if (qq == 11)globalt[ii][2]= tamp;
    20. }
    21. ii++;
    22. }

    *****************************************************************************

    有些参数太多,改起来又要重新编译,所以最好用超参数定义在外部txt文件中,其定义和读取举例如下:

    1. using namespace std;
    2. using namespace cv;
    3. bool config::GetFile(const string &filename)
    4. {
    5. if (config_ == NULL)
    6. config_ = std::shared_ptr<config>(new config);
    7. else
    8. config_->file_ = FileStorage(filename.c_str(), FileStorage::READ);
    9. if(config_->file_.isOpened() == false)
    10. {
    11. cerr<<"con not open";
    12. return false;
    13. }
    14. return true;
    15. }
    16. static T GetParameter(const string &key)
    17. {
    18. return T(config_->file_[key]);
    19. }
    20. dataset_ = Dataset::Ptr(new Dataset(Config::Get<std::string>("dataset_dir")));

    ************************************************************************8

    1. ifstream fin(dataset_path_ + "/calib.txt");
    2. if (!fin) {
    3. LOG(ERROR) << "cannot find " << dataset_path_ << "/calib.txt!";
    4. return false;
    5. }
    6. for (int i = 0; i < 4; ++i){ //一共有P0,P1,P2,P3四个相机,这里就是要把四个相机的参数全部读取到
    7. //前三个字符是P0:所以这里定义了一个长度为3的字符数组,读完这三个字符后就遇到了第一个空格,fin将会跳过这个空格,读取参数
    8. char camera_name[3];
    9. for (int k = 0; k < 3; ++k) {
    10. fin >> camera_name[k];
    11. }
    12. //将相机后面对应的12个参数读入到projection_data[12]中
    13. double projection_data[12];
    14. for (int k = 0; k < 12; ++k) {
    15. fin >> projection_data[k];
    16. }
  • 相关阅读:
    JavaScript面向对象:类的继承
    主页整理:8月1日---9月10日
    给Linux上的jupyter修改密码
    基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理
    flinksql读oracle写入mysql
    (王道考研计算机网络)第五章传输层-第三节1-5:TCP拥塞控制
    【HMS core】【FAQ】Analytics Kit、Push Kit典型问题合集3
    二、程序员指南:数据平面开发套件
    这样记账更高效
    Hadoop的HDFS的集群安装部署
  • 原文地址:https://blog.csdn.net/FL1768317420/article/details/136246903