1-百万数据[IO/sort/vector]
排序问题三步:读文件、排序、写文件
一.读文件
1.整体三秒版读文件[以行为单位的double数读入vector]
- [应用了filebuf->sgetn、ifstream.rdbuf()、istringstream、vector.reserve]
- 通过istringstream对已获取文件信息的string input作进一步操作,以换行为分隔符将每个substr用stof转换为double数后push_back入vector
//读入txt,一百万行,每行一个double数,数据存入vector
//下面重写buffer 加载char*
ifstream filestr;
long size;
char * buffer;
filebuf *pbuf;
filestr.open ("M1.txt", ios::binary);//二进制方式打开文件
pbuf = filestr.rdbuf();//利用filebuf *pbuf对ifstream输入流内容重定向
size=pbuf->pubseekoff (0,ios::end,ios::in);//获取文件字节大小,1字节==sizeof(char)
pbuf->pubseekpos (0,ios::in);//将指针位置更改为文件初始位置
buffer=new char[size];//预先为字符串分配与文件大小相同的缓冲区
pbuf->sgetn (buffer,size);//调用filebuf的sgetn()函数填充字符串缓冲区char *buffer
filestr.close();//关闭ifstream
string input(buffer);
//cout<<input<<endl;
delete []buffer;
istringstream ss_sim(input);//利用istringstream流
string fVecSim;
vec_similarity.reserve(1000000);
while(ss_sim >> fVecSim){
//cout<<fVecSim<<endl;
vec_similarity.push_back(atof(fVecSim.c_str()));//以“\n”为分隔符将文件每行的字符串转为double后添加到vector
fVecSim.clear();//清除string中的内容
}
/*和上面的while功能类似
while(ss_sim.good()){
ss_sim>>fVecSim;
vec_similarity.push_back(atof(fVecSim.c_str()));
}*/
2.有问题的快速读文件(第一版)[读入vector]
/*有问题的buffer和char*部分
ifstream iVecSim("M3.txt");
iVecSim.seekg(0,iVecSim.end);
long long file_size = iVecSim.tellg();//大小
iVecSim.seekg(0,iVecSim.beg);
char *buffer = new char[file_size];
iVecSim.read(buffer,file_size);
*/
3.来自性能优化指南的读文件方法——file_reader(),写入string,耗时0.4s
- [应用了filebuf->sgetn、ifstream.rdbuf()、istringstream、vector.reserve]
- 实际上这个方法是1的简化版
- [有时间时候需要将这两种方法结合起来,尝试进一步优化]
- [后经过检验,该方法并不如filebuf填充的效果好]
#include <iostream>
#include<fstream>
#include<stdlib.h>
#include<sstream>
#include<time.h>
#include<utility>
using namespace std;
//void stream_read_streambuf_stringstream(std::istream& f, std::string& result);
//1 这个简单的方法就可以实现把所有的文件内容读取到一个string中 0.4 s
std::string file_reader(char const* fname){
std::fstream f;
f.open(fname);
if(!f){
std::cout<<"CAN NOT OPEN"<<endl;
return "";
}
std::stringstream s;
std::copy(std::istreambuf_iterator<char>(f.rdbuf()),
std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(s));
return s.str();
}
int main()
{
//cout << "Hello world!" << endl;
// 对1的调用
//clock_t t1 = clock();
std::string s;
//std::ifstream f;
s = file_reader("M1.txt");
cout<<"OK"<<endl;
//cout<<(clock()-t1)/CLOCKS_PER_SEC *1000<<"ms"<<endl;
return 0;
}
二、读文件后检测容器大小和已知数据的匹配关系,设置数据精度
cout<<vec_similarity.size()<<endl;
cout<<std::setprecision(10);
//cout<<vec_similarity[0]<<endl;
/*
for(vector<double>::iterator it = vec_similarity.begin();it != vec_similarity.end();it++){
cout<<*it<<endl;
}
//先注释掉输出所有vector中的数据的过程:用迭代器
*/
/* //这里是测试读入vector中的内容:用下标 *测试成功
//cout<<vec_similarity.size()<<endl;
for(int i=0;i<1000;i++){
//cout<<vec_similarity[i]<<endl;
printf("%.16e\n",vec_similarity[i]);
} */
三、排序(C++内置sort)
//对vector的内容进行排序
sort(vec_similarity.begin(), vec_similarity.end());// 到这里一共1.5s 读入需要1.099s sort()需要大概0.5s
cout<<"sort succeed"<<endl;
四、写文件(※)
1.开ofstream,直接将vector写入 | [改良]利用sprintf
//1-将排好序的vector的内容写入文件中
//直接写double,改为下标访问,总时间11s
//2019-2-8 12:48 将直接输出double数改为:通过sprintf将double转换为char[] ,速度提升了4倍,降低为原时间的25%
std::ofstream res("res_directly.txt");
res << std::setprecision(10);
for(unsigned i=0; i<vec_similarity.size() ; i++){
double tmp = vec_similarity[i];
char str[30];
sprintf(str, "%.9e\n", tmp);//sprintf大法好!
res<<str;
}
cout<<"store succeed"<<endl;
2.二进制输出
/*
//2-该方法输出格式为二进制文件
int k=0;
for(vector<double>::iterator it = vec_similarity.begin();it != vec_similarity.end();it++){
da[k++] = *it;//这里对vector进行遍历不需要花多少时间 保存到了double数组da中[全局]
}
int len = sizeof(double) * vec_similarity.size();
ofstream ofile;
ofile.open("res4.txt",ios::binary);
ofile.write((const char*)da, len);
ofile.close();
*/
3.利用迭代器和std::copy进行格式化输出
/* 3-该方法1 精度不对 2时间太长 12s
std::ofstream output_file("res.txt");
std::ostream_iterator<double> output_iterator(output_file,"\n");
std::copy(vec_similarity.begin(), vec_similarity.end(), output_iterator);
*/
4.将vector元素转换为string | char* buffer指向的内容
-当将所有数据内容集中到一个string中,再一次性用ofstream 的 << 运算符,即可快速写入文件
/*//4-该方法虽然将vector中的内容全部转换为string添加到result中,但时间过长,共16s 还不如上一个方法;
//或者改为char*数组,利用sprintf 和 strcat进行拼接,更慢
//改成了下标访问,还是很慢
//想办法将vector中的内容全部保存到 char*
long size2 = sizeof(double) * vec_similarity.size();
char *buffer2 = new char[size2];
for(unsigned i=0;i<vec_similarity.size();i++){
double tmp = vec_similarity[i];
char str[30];
sprintf(str,"%.9e\n", tmp);
strcat(buffer2, str);
//cout<<str;
}
ofstream file("res5.txt");
file << buffer2; //这里直接把char* buffer2的buffer2给file 就成功地把内容写进去了 double数组名不行
cout<<"\n\n\n"; //因此考虑将double数组变为char*数组
delete []buffer2;
*/
/* 将double转换为string
result.reserve(1000000);
for(unsigned i=0; i<vec_similarity.size() ; i++){
to_string(result, vec_similarity[i]);
}
cout<<result.size()<<endl;
*/
/*
void to_string(string& result, double& T){
ostringstream oss;
oss<<T;
result.append(oss.str().c_str());
result.append("\n");
}
*/