文件的定位读写问题,请各位大佬解惑
本帖最后由 两手空空儿 于 2023-1-29 21:41 编辑我的设想是用一个文件来存放员工的【人数】和【员工信息】,添加或者删除时再更新文件的内容,示例代码如下
#include <iostream>
#include <fstream>
#include <string>
#define FILE "save.txt"
using namespace std;
class Employee{
public:
//
Employee(int num, string name, int age):m_number(num), m_name(name), m_age(age){
}
//
//private:
int m_number;
string m_name;
int m_age;
};
int main(void)
{
int cnt = 2; //员工的数量
Employee emp ={
{11, "张三", 25},
{12, "李四", 33}};
//写入数据
ofstream ofs(FILE, ios::out);
ofs << cnt << endl;
ofs << emp.m_number << " " << emp.m_name << " " << emp.m_age << endl;
ofs << emp.m_number << " " << emp.m_name << " " << emp.m_age << endl;
ofs.close();
//增加数据,问题来了。。。。。。。。。。。。。。
//单独写入cnt, 再往文件尾追加员工信息
return 0;
}
在文件中,2(cnt)这个数字是以字符形式存放的,只占文件的1个位置, cnt = 10时,就会占两个位置
随着人数的增加,当cnt为两们数,叁位数,或者更多时,
ofs << cnt << endl; 这一句会覆盖第一位员工的数据,
怎么才能解决这个问题?难道只能每次更新数据的时候把所有数据读出来,再重新写入一次?
(用另外的文件单独存放cnt是可以的,但是我不想分开存放)
有没有一种方法,让文件的开头给cnt留出足够的位置,在这之后再写入员工数据
比如 cnt是 int类型,4个字节,就用4个位置用内存的形式放进去,
或者是其它什么方法 可以插空格之类的字符填充预留的位置吧
另外如果不需要保持生成文件人类可读,可能用二进制存储这个数量也是不错的选择 dolly_yos2 发表于 2023-1-29 21:36
可以插空格之类的字符填充预留的位置吧
另外如果不需要保持生成文件人类可读,可能用二进制存储这个数量也 ...
多放很多空格会不会影响后面数据的读取?
怎么在打开文件后直接定位到第一个员工的数据的开头呢?
是不是只能在初始创建文件时就把10个空格放进去,
要是先写入cnt,再补空格,这个操作有点管繁琐,还要计算每次要补多少个空格, 一个空格占两们位置,当cnt为奇数位时,写入cnt之后的读取是不是也会不准确?
二进制存储也是会覆盖后面数据的吧, 用二进制的方式,空格来占位好像还行,我试试 不要用ascii写,用二进制写
sh-5.1$ cat main.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Employee {
public:
Employee(int num = 0, const string &name = "", int age = 0): number(num), name(name), age(age) {}
friend ostream &operator<<(ostream &os, const Employee &e) {
return os << e.number << " " << e.name << " " << e.age;
}
friend ofstream &operator<<(ofstream &ofs, const Employee &e) {
ofs.write((char *)&e.number, sizeof(e.number));
size_t size = e.name.size();
ofs.write((char *)&size, sizeof(size));
ofs.write(e.name.c_str(), size);
ofs.write((char *)&e.age, sizeof(e.age));
return ofs;
}
friend ifstream &operator>>(ifstream &ifs, Employee &e) {
ifs.read((char *)&e.number, sizeof(e.number));
size_t size; ifs.read((char *)&size, sizeof(size));
char buff; ifs.read(buff, size);
e.name = string(buff, buff + size);
ifs.read((char *)&e.age, sizeof(e.age));
return ifs;
}
private:
int number;
string name;
int age;
};
int main(void) {
Employee emp = {{11, "张三", 25}, {12, "李四", 33}};
ofstream ofs("data.dat");
ofs << emp << emp;
ofs.close();
ifstream ifs("data.dat");
Employee buff;
ifs >> buff >> buff;
ifs.close();
cout << buff << std::endl;
cout << buff << std::endl;
return 0;
}
sh-5.1$ ./main
11 张三 25
12 李四 33
sh-5.1$
sh-5.1$ cat main.cpp
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Employee {
public:
Employee(int num = 0, const string &name = "", int age = 0): number(num), name(name), age(age) {}
Employee(ifstream &ifs) {ifs >> *this;}
friend ostream &operator<<(ostream &os, const Employee &e) {
return os << e.number << " " << e.name << " " << e.age;
}
friend ofstream &operator<<(ofstream &ofs, const Employee &e) {
ofs.write((char *)&e.number, sizeof(e.number));
size_t size = e.name.size();
ofs.write((char *)&size, sizeof(size));
ofs.write(e.name.c_str(), size);
ofs.write((char *)&e.age, sizeof(e.age));
return ofs;
}
friend ifstream &operator>>(ifstream &ifs, Employee &e) {
ifs.read((char *)&e.number, sizeof(e.number));
size_t size; ifs.read((char *)&size, sizeof(size));
char buff; ifs.read(buff, size);
e.name = string(buff, buff + size);
ifs.read((char *)&e.age, sizeof(e.age));
return ifs;
}
private:
int number;
string name;
int age;
};
int main(void) {
Employee emp = {{11, "张三", 25}, {12, "李四", 33}};
ofstream ofs("data.dat");
ofs << emp << emp;
ofs.close();
/*
ifstream ifs("data.dat");
Employee buff;
ifs >> buff >> buff;
ifs.close();
*/
ifstream ifs("data.dat");
Employee buff = {ifs, ifs};
ifs.close();
cout << buff << std::endl;
cout << buff << std::endl;
return 0;
}
sh-5.1$ ./main
11 张三 25
12 李四 33
sh-5.1$
两手空空儿 发表于 2023-1-29 21:54
多放很多空格会不会影响后面数据的读取?
怎么在打开文件后直接定位到第一个员工的数据的开头呢?
是 ...
C++ 标准库的输出流可以用 std::setw 来设置位宽,自动填充空格
先输入数量时会自动跳过前缀空白字符,应该不会影响后续读取?
不过还是建议用二进制,二进制指的是用 std::basic_ostream<CharT,Traits>::write 或类似方法直接把这个变量的内存表示写进文件,这个长度(基本)是固定的,如果配合 uint32_t 之类的类型使用则可以保证其写入文件必然是 32 / CHAR_BIT 个(通常是 4 个)字节,通常也不需要做填充之类的操作 人造人 发表于 2023-1-29 22:03
谢谢大佬~~~
你的用法好高级,我要好好消化一下,
有没有哪个地方可以查询 标准类库的函数的地方,>><< 和 read, write这些东西我要好好学习一下
还有string类内的函数,现在学的有点乱 sh-5.1$ cat main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
class Employee {
public:
Employee(int num = 0, const string &name = "", int age = 0): number(num), name(name), age(age) {}
Employee(ifstream &ifs) {ifs >> *this;}
friend ostream &operator<<(ostream &os, const Employee &e) {
return os << e.number << " " << e.name << " " << e.age;
}
friend ofstream &operator<<(ofstream &ofs, const Employee &e) {
ofs.write((char *)&e.number, sizeof(e.number));
size_t size = e.name.size();
ofs.write((char *)&size, sizeof(size));
ofs.write(e.name.c_str(), size);
ofs.write((char *)&e.age, sizeof(e.age));
return ofs;
}
friend ifstream &operator>>(ifstream &ifs, Employee &e) {
ifs.read((char *)&e.number, sizeof(e.number));
size_t size; ifs.read((char *)&size, sizeof(size));
char buff; ifs.read(buff, size);
e.name = string(buff, buff + size);
ifs.read((char *)&e.age, sizeof(e.age));
return ifs;
}
private:
int number;
string name;
int age;
};
const vector<Employee> load(const string &filename) {
vector<Employee> result;
ifstream ifs(filename);
size_t size; ifs.read((char *)&size, sizeof(size));
for(size_t i = 0; i < size; ++i) result.push_back(Employee(ifs));
return result;
}
void save(const vector<Employee> &v, const string &filename) {
ofstream ofs(filename);
size_t size = v.size();
ofs.write((char *)&size, sizeof(size));
for(size_t i = 0; i < size; ++i) ofs << v;
}
ostream &operator<<(ostream &os, const vector<Employee> &v) {
bool flag = false;
for(size_t i = 0; i < v.size(); ++i) {
if(flag) os << std::endl;
flag = true;
os << v;
}
return os;
}
int main(void) {
{
vector<Employee> emp = {{11, "张三", 25}, {12, "李四", 33}};
save(emp, "data.dat");
}
vector<Employee> emp = load("data.dat");
cout << emp << endl;
return 0;
}
sh-5.1$ ./main
11 张三 25
12 李四 33
sh-5.1$
dolly_yos2 发表于 2023-1-29 21:36
可以插空格之类的字符填充预留的位置吧
另外如果不需要保持生成文件人类可读,可能用二进制存储这个数量也 ...
用二进制的方式 ,10个空格占位,这个方法是可行的
//写入数据
ofstream ofs(FILE, ios::trunc | ios::binary);
ofs << " " <<endl;
ofs.seekp(ios::beg);
ofs << cnt;
ofs.seekp(10);
ofs << emp.m_number << " " << emp.m_name << " " << emp.m_age << endl;
ofs << emp.m_number << " " << emp.m_name << " " << emp.m_age << endl;
cout << "第一次写入完成" << endl;
system("pause");
//更改人数
ofs.seekp(ios::beg);
cnt = 9999;
ofs << cnt;
ofs.close(); 两手空空儿 发表于 2023-1-29 22:25
谢谢大佬~~~
你的用法好高级,我要好好消化一下,
有没有哪个地方可以查询 标准类库的函数的地方,>>
https://cplusplus.com/reference/iostream/
https://zh.cppreference.com/w/cpp/header
https://www.apiref.com/cpp/index.html
https://cn.bing.com/
有这4个大概就够了
dolly_yos2 发表于 2023-1-29 22:10
C++ 标准库的输出流可以用 std::setw 来设置位宽,自动填充空格
先输入数量时会自动跳过前缀空白字符, ...
好的,谢谢~~~
C++标准库从哪里可以查到啊,学C的时候查了库函数让自己明白了不少,学C++又不行了,
iostream就会 << , >> , string 类用起来也不太清楚 两手空空儿 发表于 2023-1-29 22:34
好的,谢谢~~~
C++标准库从哪里可以查到啊,学C的时候查了库函数让自己明白了不少,学C++又不行了,
i ...
我赞同人造人大佬的回答,这四个网站应该足够使用了 人造人 发表于 2023-1-29 22:26
辛苦大佬啦,模版,容器 ,这些我还没学,还看不懂,哈哈哈哈哈
加油学,学完再回过头来再学习大佬的这段代码 两手空空儿 发表于 2023-1-29 22:40
辛苦大佬啦,模版,容器 ,这些我还没学,还看不懂,哈哈哈哈哈
加油学,学完再回过头来再学习大佬的 ...
^_^ 人造人 发表于 2023-1-29 22:29
https://cplusplus.com/reference/iostream/
https://zh.cppreference.com/w/cpp/header
https://www.a ...
谢谢~~~~ 全部收藏啦,把常用的东西仔细学一下 dolly_yos2 发表于 2023-1-29 22:10
C++ 标准库的输出流可以用 std::setw 来设置位宽,自动填充空格
先输入数量时会自动跳过前缀空白字符, ...
谢谢~~~ ,帮我解决了暂时的问题,二进制读写的操作我还要好好学习一下 本帖最后由 两手空空儿 于 2023-1-31 12:16 编辑
人造人 发表于 2023-1-29 21:58
不要用ascii写,用二进制写
我终于悟了,打开文件的方式是不是用binary和读写完全没什么关系,我前面以为打开方式不同决定写入和读取的方式
是不是用binary的打开方式,只影响换行符这个东西{:5_107:}
用write的方式写入数字,都不用考虑会覆盖问题,内存里怎么放的,文件里就是怎么放的
字符串加长的话会有覆盖的问题,这个要自己注意
用<<或者 fprintf 这种方式向文件里写东西是把数字转成了字符串写进去的
谢谢大佬提点 两手空空儿 发表于 2023-1-31 12:11
我终于悟了,打开文件的方式是不是用binary和读写完全没什么关系,我前面以为打开方式不同决定写入和读 ...
^_^ 两手空空儿 发表于 2023-1-31 12:11
我终于悟了,打开文件的方式是不是用binary和读写完全没什么关系,我前面以为打开方式不同决定写入和读 ...
可以看看这里对 Binary and text modes 的说法
https://en.cppreference.com/w/cpp/io/c/FILE#Binary_and_text_modes
页:
[1]