在早前,由于手机芯片太拉胯,如果非必须情况,很多朋友都不会选择更换手机。而来到2023年,可选的手机芯片更为丰富。从去年年底的骁龙8+,到今年全面铺开...
2023-01-30 3
本地每一次测试都要从控制台输入测试数据,久而久之,博主就很烦了。
所以就想着要了解文件的输入输出流,把测试数据放在txt文档里,直接从文档里读取。
从控制台获取信息并输出到控制台。不是本文的重点,附上例子带过就好。
提一句,一定要写上命名空间,否则不能直接用cin和cout!
#include <iostream>using namespace std;void cinAndCout(){ cout<<"请输入信息:"<<endl; string a; cin>>a; cout<<"你输出的信息为: "<<a;}int main() { cinAndCout(); return 0;}
image-20220828220137609
iostream是可以从键盘获取输入信息;而fstream则是可以从TXT等文件中获得信息的。必须要包含下面的两个头文件才行。
#include <iostream>#include <fstream>
使用open方法建立链接,文件路径有两个办法。
也定义下列常量,来标明建立的链接是哪个模式的。
常量解释app每次写入前寻位到流结尾binary以二进制模式打开in为读打开out为写打开trunc在打开时舍弃流的内容ate打开后立即寻位到流结尾
后来,为了方便,也可以直接在生成类对象的时候直接传入文件名称和模式。为了方便理解,就直接附在后文的例子中了。
直接在对象上调用close方法就可以了。
ifstream fin("input.txt");//fstream fin("input.txt", ios::in);//等价于上一行 if (!fin) { cout << "打开文件出错" << endl; return ; }
逐行读入,是需要引入string.h头文件的。而且逐行读取的字符串,是没有换行符的!
string s;while(getline(fin,s)){ cout<<s<<endl;}
忽略空格与回车。
char c;while (!fin.eof()){ fin >> c; cout<<c<<endl;}
包括空格与回车。
char c;fin >> noskipws;while (!fin.eof()){ fin>>c; cout<<c<<endl;}
先打开文件流,往流里面插入数据信息,然后关闭文件流。
#include <fstream>#include<iostream>#define filepath "/Volumes/KeenMacPlus/Projects/C++项目/KeenCPPTest-all/STL/fstream/txt/"using namespace std;/* * 向文件中写入字符串,注意模式的不同 * */void write(){ // ofstream fout(filepath"input.txt");写入流,覆盖模式 fstream fin; // fin.open(filepath"input.txt"); // 覆盖模式 fin.open(filepath"input.txt", ios::app); // 末尾追加模式 if (!fin) { cout << "打开文件出错" << endl; } fin << "这是新加的一行" << endl; fin.close();}
image-20220828191911146
image-20220828191919756
#include<iostream> #include<fstream> using namespace std;void read() { // ifstream fin("input.txt");//等价于下两行 fstream fin; fin.open(filepath"input.txt", ios::in); if (!fin) { cout << "打开文件出错" << endl; } char c; int lineNum = 0;// 统计行数 while (fin.get(c))// 逐字符读入 { if (c == '\n') lineNum++; } cout << lineNum + 1 << endl; fin.close();}
之前是用cin和cout从控制台获得信息,重定向后可以用这两个对象操作文件写入写出!
#include<fstream>#include <ostream>#include <iostream>#include<string>#define filepath "/Volumes/KeenMacPlus/Projects/C++项目/KeenCPPTest-all/STL/fstream/txt/"using namespace std;void cinAndCout() { cout << "请输入信息:" << endl; string a; cin >> a; cout << "你输出的信息为: " << a;}int main() { // cinAndCout(); ifstream fin(filepath"rdbuf.txt"); ofstream fout(filepath"out.txt"); if (!fin || !fout) { cout << "打开文件出错" << endl; return 0; } // 下面四行是用 rdbuf() 重新定向 streambuf *cinbackup = NULL; streambuf *coutbackup = NULL; coutbackup = cout.rdbuf(fout.rdbuf()); cinbackup = cin.rdbuf(fin.rdbuf()); // 用 rdbuf() 重新定向 // 原先这个对象是输出到控制台,限制是输出到文件out.txt cout << "Hello world" << endl; string line; while (cin) { cin >> line;// 从 rdbuf.txt 文件读入 if (cin) cout << line << endl;// 写入 out } fout.close(); fin.close(); //恢复标准输入输出 // 如果不恢复,即使关闭了文件流,仍然无法输出到控制台! cin.rdbuf(cinbackup); // 恢复键盘输入 cout.rdbuf(coutbackup); // 恢复控制台输出 cout << "完成操作!"; return 0;}
一共有两种实现逻辑,分别是针对大文件和小文件的。
不论是修改还是删除,其实底层逻辑其实是一样的。
第一步是读取原来的文件,一般是for循环逐行读取。
第二步是在循环的过程中匹配行号或者关键字,当匹配成功就对内容进行修改或者舍弃
第三步,则是将读到内存的信息流写入文件,目标可以是新的文件,也可以是原来的文件。
按照缓存数据的方式可以分为两种,一种是针对大文件,短时间内无法完成全部操作,这时候我建议使用中间文件做缓存,即使出现意外也有之前留下的内容;而对于小文件,则是可以选择将文件内容全部存到内存里面来,然后再一次性覆盖回原来的文件。
其实删除某一行内容也是属于这种操作,整体文件流区别变化是不大的。
/* * 修改指定行号的数据为新的内容 * 三个参数分别是文件名,行号,要修改的内容 * 底层逻辑是把文件信息全存储到中间文件里,然后再把中间文件的内容覆盖源文件的内容 * * 好处是即使出错了或者断电了,那么之前的数据仍然是保留在中间文件中的 * 坏处是要读写量增大了,很耗费时间,适合大文件 * */void modiFile(string filename, int lineNum, string str) { ifstream file(filename); string line; // 临时变量,读取文件的一行内容 int num = 0;// 统计行号 ofstream outfile("test.txt", ios::out | ios::trunc);//用中间文件,记录整个文件的信息 //将信息从源文件写到中间文件 while (!file.eof()) { getline(file, line); if (num != lineNum - 1) outfile << line << endl; else outfile << str << endl; num++; } outfile.close(); file.close(); // 将信息从中间文件写入到源文件 ofstream outfile1(filename, ios::out | ios::trunc); fstream file1("test.txt"); while (!file1.eof()) { getline(file1, line); if (line != "") { outfile1 << line << endl; } } outfile1.close(); file1.close(); //最后删除中间文件 // system("del test.txt");//Windows system("rm -f test.txt");// mac和linux}
/* * 修改指定行号的数据为新的内容 * 三个参数分别是文件名,行号,要修改的内容 * 底层逻辑是把文件信息全存储到字符串变量outStr里,然后再覆盖原先的内容 * * 好处是不需要生成另一个临时文件来存储内容,适合小文件。 * 缺点就是一旦在过程中出错了或者断电了,那么之前的数据就全没有了! * */void modiFile2(string filename, int lineNum, char *content) { ifstream in(filename); string line; // 临时变量,读取文件的一行内容 int num = 0;// 统计行号 string outStr;// 记录整个文件的数据流 while (getline(in, line)) {// 逐行读取,是没有换行符的! num++; if (lineNum != num) { outStr += line; } else { outStr += content; } outStr += '\n'; } in.close(); //新建这个文件的写入流对象,调用flush函数来清空文件流内的内容。 ofstream out; out.open(filename); out.flush(); out << outStr; out.close();}
因为以前的.cpp文件很多都是GBK编码的,现在为了统一称为UTF8编码的。在Linux系统上面有一个iconv命令。
: 切换到指定路径cd /Volumes/KeenMacPlus/Projects/C++项目/KeenCPPTest-all: find命令,在Convert_UTF8的文件夹中生成相同名称的路径树find ./KeenCPPTest-all -type d -exec mkdir -p Convert_UTF8/{} \;: find命令 -exec 是找到文件后运行脚本命令: 双引号中的脚本内容,是将文件转码后放到指定的文件夹下: 最后 \; 是find -exec的终止标志find ./KeenCPPTest-all -exec sh -c "iconv -f GBK -t utf-8 {} > Convert_UTF8/{}" \;
源码文件:
gitee:https://gitee.com/JunKuangKuang/KeenCPPTest-all/tree/main/STL/fstream
github.com:https://github.com/JunKuangKuang/KeenCPPTest-all/blob/main/STL/fstream
参考我以前存留的cpp文件,感谢以前努力的自己。
参考张成的博客
使用iconv批量转码
相关文章
在早前,由于手机芯片太拉胯,如果非必须情况,很多朋友都不会选择更换手机。而来到2023年,可选的手机芯片更为丰富。从去年年底的骁龙8+,到今年全面铺开...
2023-01-30 3
对于现在的手机来说,内置的不可拆卸的电池俨然已经成为了一种行业标准,而更大的电池设计、更高功率的充电和移动电源便是现时续航焦虑的解决方法。不过话虽如此...
2023-01-30 1
生活中,有些业主因对物业公司划定公共区域停车位并收费的行为不满而诉至法院。那么,不满物业收取公共区域停车费,单个业主可以提起诉讼吗?法律对此又有怎样的...
2023-01-30 2
玩法类似《守望先锋》的《高达:进化》即将迎来游戏的第三季内容更新。今天(1月30日),Bandai Namco官方公布了一段视频,对游戏第三季的新增机...
2023-01-30 2
在LOL里,有很多针对对抗贾克斯的英雄,下面我就来逐一介绍一下:1、吉安娜:吉安娜是一个强大的近战英雄,同时也是一个非常强大的应对贾克斯英雄。利用自己...
2023-01-30 1
本文首发【提瓦特营地】,未经授权禁止“抄袭文章”转载至其它平台。各位小伙伴们大家好呀,这里是筱筱。很多小伙伴给筱筱发来留言,在抽到了中意的主C之后不知...
2023-01-30 2
虽然原神的角色设计各有千秋,而且大部分是0命就能玩的强度。但是个别角色0命状态下,横向对比真的不如其他五星角色,不冲命座,强度真的会有点尴尬。为什么咱...
2023-01-30 1
近日,PS APP迎来更新,官方为其添加了外观自定义功能,用户可设置7种软件外观颜色,正好对应手柄配色。 前段时间,玩家们对于PS5主题功能的呼声非常...
2023-01-30 1
最新留言