我有一个struct
,它描述了存储在二进制文件中的数据对象。该结构看起来像:
struct Sum_str {
public:
char FINISH_T[24]; // U4
char DISP_COD; // C1
char USR_DESC[128]; // Cn
char EXC_DESC[128]; // Cn
};
这是通过读取二进制文件加载的,并且文件中数据对象的数量可能有所不同。当我通过struct
将const
声明为设置限制时,一切正常。不幸的是,二进制文件可以具有比声明的更少或更多的数据。
如何根据二进制文件中存储的对象数量,根据需要动态增长数组?
答案 0 :(得分:0)
如果数组的大小可以大于给定的最大值(24、128、128),则说明您使用的容器不是正确的。如果您需要容器的大小是动态的,请使用向量代替数组
struct Sum_str {
public:
std::vector<char> FINISH_T; // U4
char DISP_COD; // C1
std::vector<char> USR_DESC; // Cn
std::vector<char> EXC_DESC; // Cn
};
如果限于阵列,则仅按其各自的长度填充阵列。请记住,在数据的末尾放置空终止符,以免在打印内容时意外读取char数组。另外,对数组大小使用#define代替魔术数字。
如果不确定需要多少Sum_str结构,则应使用适合您要求的容器。您的要求需要一个可以改变大小的容器,因此您应该使用vector
std::vector<Sum_str> my_container;
答案 1 :(得分:0)
您没有指定二进制文件的实际格式,因此我将假定它包含您提供的结构数组。
因此您的基本算法将如下所示:
std::vector
一样创建结构的std:vector <Sum_str > myVect;
myVect.push_back(obj);
主要和从属假设是二进制文件包含等于结构数组Sum_str
的二进制映像的零个或多个。这很重要的原因是您要确保:
Sum_str
对象的大小与内存中Sum_str
对象的大小Sum_str
对象的成员的布局和偏移与内存中Sum_str
对象的成员的布局和偏移如果二进制文件仅包含结构数据数组,则您可能需要估计文件中包含的结构数,并以近似于估计的初始容量创建std::vector
。请参阅Initial capacity of vector in C++和Using C++ filestreams (fstream), how can you determine the size of a file?,其中提供了一种计算文件大小的方法。尽管在Windows和Linux上的二进制文件看起来已经足够接近了,但是tellg()
这种获取文件大小的方法并不可靠。
请参见Reading and writing binary file和How to read a binary file into a vector of unsigned chars以及c++ Read/Write class from/to binary file和C++ binary files and iterators: getting away with a 1:1 using ifstreambuf_iterator?。
首次剪切-使用较早版本的C ++进行的简单演示
我在哪里没有C ++ 11/17,所以这里是一个使用较旧的C ++编译器的版本,直到我可以使用较新的版本并可以进行一些研究为止。
#include <iostream>
#include <fstream>
#include <vector>
struct Person
{
char name[50];
int age;
char phone[24];
};
int mainx()
{
Person me = {"Robert", 28, "364-2534"};
Person book[30];
int x = 123;
double fx = 34.54;
// put in some data for our output to show that it works.
for (int i = 0; i < 30; i++) {
book[i] = me;
book[i].age = i *10 + 5; // modify the age so we can see it changed.
}
std::ofstream outfile;
outfile.open("junk.dat", std::ios::binary | std::ios::out);
outfile.write((char *)&x, sizeof(int)); // sizeof can take a type
outfile.write((char *)&fx, sizeof(fx)); // or it can take a variable name
outfile.write((char *)&me, sizeof(me));
outfile.write((char *)book, 30*sizeof(Person));
outfile.close();
return 0;
}
int mainy()
{
Person me = {0};
std::vector<Person>book;
int x = 0;
double fx = 0;
std::ifstream infile;
infile.open("junk.dat", std::ios::binary | std::ios::in);
infile.read((char *)&x, sizeof(int)); // sizeof can take a type
infile.read((char *)&fx, sizeof(fx)); // or it can take a variable name
infile.read((char *)&me, sizeof(me));
for (int i = 0; i < 30; i++) {
Person buff;
infile.read((char *)&buff, sizeof(Person));
book.push_back(buff);
}
infile.close();
std::cout << "x = " << x << std::endl;
std::cout << "fx = " << fx << std::endl;
std::cout << "Person me = " << me.name << ", age " << me.age << ", phone " << me.phone << std::endl;
for (int i = 0; i < 30; i++) {
std::cout << "Person book = " << i << " " << book[i].name << ", age " << book[i].age << ", phone " << book[i].phone << std::endl;
}
return 0;
}
int main ()
{
mainx();
mainy();
return 0;
}
附录-使用迭代器进行演示
这是上面修改为使用迭代器的第二个示例。这不是我的专业领域,但是我在控制台应用程序中使用Visual Studio 2017进行的测试表明它可以正常工作。
#include <iterator>
#include <iostream>
#include <fstream>
#include <vector>
struct Person
{
char name[50];
int age;
char phone[24];
friend std::ostream& operator<<(std::ostream& os, const Person& dt);
friend std::istream& operator<<(std::istream& os, const Person& dt);
};
std::ostream& operator<<(std::ostream& os, const Person& dt)
{
os.write((char *)&dt, sizeof(Person));
return os;
}
std::istream& operator>>(std::istream& os, const Person& dt)
{
os.read((char *)&dt, sizeof(Person));
return os;
}
// construct a binary file that contains various objects.
// in the following routine we will read back out from
// the binary file the objects we wrote into it.
int mainx()
{
Person me = { "Robert", 28, "364-2534" };
std::vector<Person> book;
int x = 123;
double fx = 34.54;
// put in some data for our output to show that it works.
for (int i = 0; i < 30; i++) {
Person x = me;
x.age = i * 10 + 5; // modify the age so we can see it changed.
book.push_back (x);
}
// construct out output file with the various objects
// we want to save. when we read from this file
// we will want to use the same types of variables
// in the same order since there is no meta data
// in this file to indicate object types or object boundaries.
std::ofstream outfile("junk.dat", std::ios::binary | std::ios::out);
outfile << x;
outfile << fx;
outfile << me;
// write out the vector of Person objects.
for (auto x : book) outfile << x;
outfile.close();
return 0;
}
// following routine opens the persistent store and reads
// back in the objects that were saved. we need to do
// the reading in the same order they were written.
int mainy()
{
Person me = { 0 };
int x = 0;
double fx = 0;
std::ifstream infile("junk.dat", std::ios::binary | std::ios::in);
infile >> x;
infile >> fx;
infile >> me;
// istream_iterator from stream infile
std::istream_iterator<Person> is(infile);
// End-of-stream iterator
std::istream_iterator<Person> isEof;
std::vector<Person>book;
// iterate over the Person objects in the input
// stream until end of file pushing each object
// read into our vector.
while (is != isEof) {
book.push_back(*is);
is++;
}
infile.close();
std::cout << "x = " << x << std::endl;
std::cout << "fx = " << fx << std::endl;
std::cout << "Person me = " << me.name << ", age " << me.age << ", phone " << me.phone << std::endl;
int i = 0;
for (auto x : book) {
i++;
std::cout << "Person book = " << i << " " << x.name << ", age " << x.age << ", phone " << x.phone << std::endl;
}
return 0;
}
int main()
{
mainx(); // write the binary file
mainy(); // read the binary file
return 0;
}