[C++]文件读写操作

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

步骤2:创建流对象

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

如:

ifstream  fin;
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:向流中写入数据,最后关闭流

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

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

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

if(!fin.is_open())
{
    std::cerr<<"cannot open the file"
}
//或者
if(!fin)
 {
    std::cerr<<"cannot open the file";
}  

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

//申请读空间:
char buf[1024]={0}; 就是临时申请一个 1024大的读空间(又叫buffer),并且初始化为0。
while (fin >> buf)
    {
        cout << buf << endl;//每一次的buf是空格或回车键(即白色字符)分开的元素
    }
文件:
1 2 3
a b c
112
geya
读取结果:
1
2
3
a
b
c
112
geya

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

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

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

getline:

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

char buf[1021]={0};
while(fin.getline(buf,sizeof(buf)))
    
 {
    std::cout<<buf<<std::endl;
    
} 
文件:
1 2 3
a b c
112
geya
读取结果:
1 2 3
a b c
112
geya

第三种读的方式(get):

char c;
while ((c = fin.get()) != EOF)
{
   std::cout << c;
} 
文件:
1 2 3
a b c
112
geya
读取结果:
1 2 3
a b c
112
geya

第四种读的方式:

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

char a,s1,s2,s3,s4,s5;
std::string s6;
fin >> a >> s1 >> s2 >> s3>>s4>>s5>>s6;
std::cout<<a<<" "<<s1<<" "<<s2<<" "<<s3<<" "<<s4<<" "<<s5<<" "<<s6;
文件:
1 2 3
a b c
112
geya
读取结果:
1 2 3 a b c 112

步骤5:数据类型转换

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

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

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

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

#include "libHelloSLAM.h"
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include <sstream>
struct people{
    std::string name;
    std::vector<int> phonenum;
};
int main( int argc, char** argv )
{
std::ifstream fin;
fin.open("/home/bing/slambook14/slambook/ch2/test.txt",std::ios::in);
if(!fin.is_open())
{
    std::cerr<<"cannot open the file";
    
}
char line[1024]={0};
std::vector<people> People;
//从文件中提取"行"
while(fin.getline(line,sizeof(line)))
{
    //定义局部变量
    people p;
    //从"行"中提取"单词"
    std::stringstream word(line);
    word>>p.name ;
    int num;
    while(word>>num)
        p.phonenum.push_back(num);
    People.push_back(p);
}
 std::cout<<People[1].name<<"'s phonenumber is:"<< People[1].phonenum[1];  
  
}
文件:
gyb 1333 12212
lck 212  33113
ddl 332  41311

输出:
lck's phonenumber is:33113

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

//从文件中提取"行"

fin.getline(line,sizeof(line))

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

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

如:

#include <string>
#include <sstream>
#include <iostream>
#include <stdio.h>
using namespace std;
 int main()
{
    stringstream sstream;
    string strResult;
    int nValue = 1000;
 
    // 将int类型的值放入输入流中
    sstream << nValue;
    // 从sstream中抽取前面插入的int类型的值,赋给string类型
    sstream >> strResult;
     cout << "[cout]strResult is: " << strResult << endl;
    printf("[printf]strResult is: %s\n", strResult.c_str());
//这里的  str() 方法是将 stringstream 类型转换为 string 类型
     return 0;
}

其他:

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

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

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

写:cin>>word

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

如:

while(word>>num){}

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

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

void LoadImages(const string &strPathToSequence, vector<string> &vstrImageFilenames, vector<double> &vTimestamps)
{
    // step 1 读取时间戳文件
    ifstream fTimes;
    string strPathTimeFile = strPathToSequence + "/times.txt";
    fTimes.open(strPathTimeFile.c_str());
    while(!fTimes.eof())
    {
        string s;
        getline(fTimes,s);
        // 当该行不为空的时候执行
        if(!s.empty())
        {
            stringstream ss;
            ss << s;
            double t;
            ss >> t;
            // 保存时间戳
            vTimestamps.push_back(t);
        }

    string strPrefixLeft = strPathToSequence + "/image_0/";
    const int nTimes = vTimestamps.size();
    vstrImageFilenames.resize(nTimes);

    for(int i=0; i<nTimes; i++)
    {
        stringstream ss;
        ss << setfill('0') << setw(6) << i;
        vstrImageFilenames[i] = strPrefixLeft + ss.str() + ".png";
    }

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

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

string filename="./test.txt"

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

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

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

读特定列:

int main()
{
ifstream ff1;
ff1.open("/home/bing/ORB/ORB_SLAM2/LiGT/LiGT_results.txt");
char line[1024] = {0};

if(!ff1.is_open()) cerr<<"can not open";

float globalt[1000][3];
int ii=0;
while(ff1.getline(line,sizeof(line)))
{

std::stringstream word(line);
for(int qq=0;qq<12;qq++)
{
    float tamp;
    word>>tamp;
//   cout<< tamp<< "   "<<qq<<endl;
if (qq == 9)    globalt[ii][0] = tamp;
if (qq == 10)globalt[ii][1] = tamp;
if (qq == 11)globalt[ii][2]= tamp;
}
ii++;
}

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

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

using namespace std;
using namespace cv;
 bool config::GetFile(const string &filename)
{
    if (config_ == NULL)
          config_ = std::shared_ptr<config>(new config);
    else
        config_->file_ = FileStorage(filename.c_str(), FileStorage::READ);
    
    if(config_->file_.isOpened() == false)
    {
        cerr<<"con not open";
        return false;
    }
    return true;
    
}
static T GetParameter(const string &key)
{
    return T(config_->file_[key]);
    
}


dataset_ = Dataset::Ptr(new Dataset(Config::Get<std::string>("dataset_dir")));

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

 ifstream fin(dataset_path_ + "/calib.txt");
 if (!fin) {
 LOG(ERROR) << "cannot find " << dataset_path_ << "/calib.txt!";
 return false;
        }

 for (int i = 0; i < 4; ++i){   //一共有P0,P1,P2,P3四个相机,这里就是要把四个相机的参数全部读取到
            //前三个字符是P0:所以这里定义了一个长度为3的字符数组,读完这三个字符后就遇到了第一个空格,fin将会跳过这个空格,读取参数
 char camera_name[3];
 for (int k = 0; k < 3; ++k) {
 fin >> camera_name[k];
            }

            //将相机后面对应的12个参数读入到projection_data[12]中
 double projection_data[12];
 for (int k = 0; k < 12; ++k) {
 fin >> projection_data[k];
            }
相关推荐
奋飞安全2 分钟前
初试js反混淆
开发语言·javascript·ecmascript
guoruijun_2012_42 分钟前
fastadmin多个表crud连表操作步骤
android·java·开发语言
浪里个浪的10245 分钟前
【C语言】计算3x3矩阵每行的最大值并存入第四列
c语言·开发语言·矩阵
@东辰12 分钟前
【golang-技巧】-自定义k8s-operator-by kubebuilder
开发语言·golang·kubernetes
乐悠小码18 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.20 分钟前
Pod控制器
java·开发语言
敲敲敲-敲代码29 分钟前
游戏设计:推箱子【easyx图形界面/c语言】
c语言·开发语言·游戏
ROC_bird..38 分钟前
STL - vector的使用和模拟实现
开发语言·c++
机器视觉知识推荐、就业指导38 分钟前
C++中的栈(Stack)和堆(Heap)
c++
MavenTalk43 分钟前
Move开发语言在区块链的开发与应用
开发语言·python·rust·区块链·solidity·move