问题:将文件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;
}