C++读入文件和输出文件操作

问题:将文件file.txt中内容读入,处理后输出到另一个文件output.txt。
file.txt内容:
name age sex score
Alice 21 F 100
Ryan 30 M 97
。。。若干行
要求输出到output.txt中的内容是:(即每一行变成每一列)
name Alice Ryan 。。。若干列
age 21 30 。。。
sex F M 。。。
score 100 97 。。。

1、简单但是没考虑内存是否足够的方法

  • 将每一行读入的string用空格分割后存入vector<string> v_str
  • 然后将所有行的vector<string> v_str存入到一个大的vector< vector<string> > vv_str;
  • 然后遍历输出第i行,每行的元素是遍历输出v_str[i]各字符串
#include<vector>
//#include<iostream>
#include<fstream>
#include<string>

using namespace std;

//字符串分割函数
void string_split(const string &str, vector<string> &v_str, const string &delim)
{
    int pos1 = 0, pos2 = 0;
    int len = str.length();
    while (pos1 < len && pos2 != string::npos)
    {
        int count = 0;
        pos2 = str.find_first_of(delim, pos1);
        if (pos2 != string::npos)
        {
            if (pos1 < pos2)
            {
                count = pos2 - pos1;
            }
        }
        else if (pos1<len)
        {
            //pos2到了最后字符串末尾
            count = len - pos1;
        }

        if (count > 0)
        {
            string temp = str.substr(pos1, count);
            v_str.push_back(temp);
        }
        pos1 = pos2 + 1;
    }
}

int main()
{
    ifstream in("file.txt");
    if (!in.is_open())
    {
        return 1;
    }
    vector<vector<string>> vv_str;
    //分割读入的每一行字符串,并存入分割出的字符串数组到vv_str
    while (!in.eof())
    {
        char buffer[100];
        in.getline(buffer, 100);
        vector<string> temp;
        string_split(buffer, temp, " ");
        vv_str.push_back(temp);
    }
    in.close();

    //从vv_str输出字符串到output.txt
    ofstream out("output.txt");
    if (!out.is_open())
    {
        return 1;
    }
    //确定原始数据有多少列,就输出多少行
    int len = vv_str[0].size(); //第一行的列数
    for (int i = 0; i<len; i++)
    {
        for (vector<string> v_s : vv_str)
        {
            out << v_s[i] << " ";
        }
        out << '\n';    //完成一行输出
    }
    out.close();
    return 0;
}

各类的关系

代码中用到的文件相关的打开文件只读类ifstream和只写类ofstream,和既可读又可写文件的类fstream你需要引入头文件<fstream>。 ios::in|ios::out|ios::binary是可选参数
打开输入的文件流:ifstream in("file.txt");
打开要输出的文件流:ofstream out("output.txt")
若是用可读写的类也可以:fstream in("file.txt");
——等价于:fstream fio; fio.open('file.txt', ios::in|ios::out|ios::binary);先定义类对象,再调用函数打开。后面的参数自选需要的,读默认用了ios::in,写默认用了ios::out。
打开文件后判断是否成功打开if(! fio.is_open()) { //打开失败退出 }
关闭文件,直接调用fio.close();
判断文件读到末尾的函数:while(! fio.eof()){ //未到末尾,继续读}
读出一行数据:char buffer[100]; fio.getline(buffer, 100);
写入一行数据到文件末尾:fio<<buffer;

2、更好的方法读一行数据就写一列数据到另一个文件,重点要用到文件读写位置的操作

获得和设置流指针(get and put stream pointers)
所有输入/输出流对象(i/o streams objects)都有至少一个流指针:
ifstream, 类似istream, 有一个被称为get pointer的指针,指向下一个将被读取的元素。
ofstream, 类似 ostream, 有一个指针 put pointer ,指向写入下一个元素的位置。
fstream, 类似 iostream, 同时继承了get 和 put
我们可以通过使用以下成员函数来读出或配置这些指向流中读写位置的流指针:

  • tellg() 和 tellp()——返回文件指针位置
    这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++ 标准) ,就是一个整数,代表当前get 流指针的位置 (用tellg) 或 put 流指针的位置(用tellp).

  • seekg() 和seekp()——设置文件指针的位置
    这对函数分别用来改变流指针get 和put的位置。两个函数都被重载为两种不同的原型:

seekg ( pos_type position );
seekp ( pos_type position );

使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。

seekg ( off_type offset, seekdir direction );
seekp ( off_type offset, seekdir direction );

使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。它可以是:
ios::beg 从流开始位置计算的位移
ios::cur 从流指针当前位置开始计算的位移
ios::end 从流末尾处开始计算的位移
流指针 get 和 put 的值对文本文件(text file)和二进制文件(binary file)的计算方法都是不同的,因为文本模式的文件中某些特殊字符可能被修改。由于这个原因,建议对以文本文件模式打开的文件总是使用seekg 和 seekp的第一种原型,而且不要对tellg 或 tellp 的返回值进行修改。对二进制文件,你可以任意使用这些函数,应该不会有任何意外的行为产生。

针对上面那个问题,就可以读入一行然后写入一列到output.txt文件。关键就在于写入一列的时候需要怎么定位到每一行的末尾再写入一个元素。比如可以用一个vector<off_type>记录每次输入一列后各行的行尾位置相对于该行行首的位移。

#include<vector>
#include<iostream>
#include<fstream>
#include<string>

using namespace std;

//字符串分割函数
void string_split(const string &str, vector<string> &v_str, const string &delim)
{
    int pos1 = 0, pos2 = 0;
    int len = str.length();
    while (pos1 < len && pos2 != string::npos)
    {
        int count = 0;
        pos2 = str.find_first_of(delim, pos1);
        if (pos2 != string::npos)
        {
            if (pos1 < pos2)
            {
                count = pos2 - pos1;
            }
        }
        else if (pos1<len)
        {
            //pos2到了最后字符串末尾
            count = len - pos1;
        }

        if (count > 0)
        {
            string temp = str.substr(pos1, count);
            v_str.push_back(temp);
        }
        pos1 = pos2 + 1;
    }
}

int main()
{
    ifstream in("file.txt");
    if (!in.is_open())
    {
        return 1;
    }
    ofstream out("output.txt", ios::binary);
    if (!out.is_open())
    {
        return 1;
    }

    //分割读入的每一行字符串,然后写一列到输出文件
    //v_offset向量保存下一行末尾相对于上一行末尾的位移,也就是当前行写入的字符个数
    vector<fstream::off_type> v_offset;
    int rrows = 0;  //读取的行数
    int wrows = 0;  //写入的行数
    while (!in.eof())
    {
        rrows++;
        char buffer[256];
        in.getline(buffer, 256);
        vector<string> temp;
        fstream::pos_type pos1, pos2;
        string_split(buffer, temp, " ");
        if (1 == rrows)
        {
            //初始化v_offset,找到要写入的行数
            wrows = temp.size();
            vector<fstream::off_type> v_off_temp(wrows, 0);
            v_offset = v_off_temp;
        
            for (int i = 0; i < wrows; i++)
            {
                pos1 = out.tellp();
                out << temp[i];
                pos2 = out.tellp();
                v_offset[i] = pos2 - pos1;
                out << endl;
            }
        }
        else
        {
            //将输出流指针回到文件初始位置
            out.seekp(ios::beg);
            //读入的后面各行分别写到各列
            for (int i = 0; i < wrows; i++)
            {
                pos1 = out.tellp();
                out.seekp(v_offset[i], ios::cur);   //将流指针设置为当前位置的偏移量
                out << ' ' << temp[i];
                pos2 = out.tellp();
                v_offset[i] = pos2 - pos1;
                out << endl;
            }
        }
    }
    in.close();
    out.close();

    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容