我正在编写代码以读取大型.xyz文件。这些类型的文件对于分子动力学可视化工具(如VMD)很有用。所以文件格式看起来像这样
#Number of particles
#frame number
#Coordinates
例如:
5
0
C 1.23 2.33 4.56
C 1.23 2.33 5.56
C 1.23 2.33 6.56
C 1.23 2.33 7.56
C 1.23 2.33 8.56
5
1
C 2.23 2.33 4.56
C 2.23 3.33 5.56
C 2.23 4.33 6.56
C 2.23 5.33 7.56
C 2.23 6.33 8.56
,依此类推。 我试图在此处https://codereview.stackexchange.com/questions/201743/processing-xyz-data-from-a-large-file上理解这篇文章,该文章讨论了使用运算符重载方法从大型数据集中有效读取的内容。我正在尝试编写一个可以读取如此大的轨迹文件并提供以下输出的类:1)粒子数量2)帧总数3)每个时间步长的坐标集。所以我试图根据这篇文章写下以下内容,以上述文件格式阅读。到目前为止,下面的代码能够读取单个帧并在此之后退出。
#include <iostream>
#include <vector>
#include <fstream>
struct Particle{
long double x,y,z;
char tab ='\t';
char newline = '\n';
char atom ;
friend std::istream& operator>>(std::istream& in, Particle &xyz) {
in >> xyz.atom >> xyz.x >> xyz.y >> xyz.z ;
return in;
}
friend std::ostream& operator<<(std::ostream& out, Particle &xyz){
out << xyz.x << xyz.tab << xyz.y << xyz.tab << xyz.z << xyz.newline;
return out;
}
};
class XYZ_frame_read
{
int curr_frame;
int num_particles;
std::vector<Particle> coordinates_t;
public:
friend std::istream& operator>>(std::istream& in, XYZ_frame_read &traj ){
in >> traj.num_particles;
in >> traj.curr_frame;
Particle p;
while(in >> p){
traj.coordinates_t.push_back(p);
}
return in;
}
friend std::ostream& operator<<(std::ostream& out, XYZ_frame_read &traj){
for(int i = 0; i< traj.num_particles ;i ++){
out << traj.coordinates_t.at(i) ;
}
return out;
}
};
int main(int argc, char *argv[]){
std::ifstream in(argv[1]);
XYZ_frame_read* frames = new XYZ_frame_read[3];
in >> frames[0];
std::cout << frames[0];
return 0;
}
问题是我不知道如何实现此方法来读取下一个帧,并继续将它们添加到对象coordinates_t
的每个实例的XYZ_frame_read
向量中。我想我知道这是如何工作的,显然while(!in.eof())
毫无疑问,因为它只会一遍又一遍地读取第一帧。我是C ++的新手,正在从事与分子动力学相关的项目,欢迎任何更改/建议!!谢谢您的帮助!
编辑
我尝试使用
size_t i = 0;
while(in >> frames[i]){
std::cout << frames[i];
if(i == 3){
break;
}
i++;
}
它返回空白。没用循环甚至没有执行。
答案 0 :(得分:0)
while(!in.eof())
是不可能的,因为eof
不能那样工作。
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
我不确定是否看到问题,这是怎么回事
size_t i = 0;
while (in >> frames[i])
++i;
(除了数组边界错误的可能性)。
编辑
此代码不正确
friend std::istream& operator>>(std::istream& in, XYZ_frame_read &traj) {
in >> traj.num_particles;
in >> traj.curr_frame;
Particle p;
while(in >> p){
traj.coordinates_t.push_back(p);
}
return in;
}
这表示继续读取粒子,直到读取失败。那是不正确的,您知道有多少粒子。应该说继续读取粒子,直到您读取了num_particles
个粒子(否则读取失败)。即应该说
friend std::istream& operator>>(std::istream& in, XYZ_frame_read &traj) {
in >> traj.num_particles;
in >> traj.curr_frame;
Particle p;
for (int i = 0; i < traj.num_particles && in >> p; ++i)
traj.coordinates_t.push_back(p);
}
return in;
}
答案 1 :(得分:0)
您非常亲密,您只需要在重载的运算符函数中验证输入,而不必使用new
!,而只需使用std::vector<XYZ_frame_read> frames;
例如,istream
的{{1}}过载,您所需要做的就是:
class XYZ_frame_read
然后在 friend std::istream& operator>>(std::istream& in, XYZ_frame_read &traj)
{
/* validate that num_particles and curr_frame read */
if (in >> traj.num_particles >> traj.curr_frame) {
int n = traj.num_particles; /* set number of particles to read */
Particle p;
while (n-- && (in >> p)) /* read that number of particles */
traj.coordinates_t.push_back(p);
}
return in;
}
中进行分配,而不是像在此处那样为main()
分配new
:
frames
只需使用 XYZ_frame_read* frames = new XYZ_frame_read[3];
in >> frames[0];
std::cout << frames[0];
,然后使用临时 std::vector<XYZ_frame_read> frames;
来验证读取,然后再将其添加到帧向量中,例如
class XYZ_frame_read
对于输出,只需使用自动调整范围的 std::vector<XYZ_frame_read> frames; /* vector of frames (NO new!) */
for (;;) { /* continual loop while good input */
XYZ_frame_read tmp; /* temp XYZ_frame_read for read */
if ((in >> tmp)) /* if read is good */
frames.push_back(tmp); /* add it to vector of frames */
else
break; /* otherwise -- bail */
}
循环,例如
for
将其完全放在一起,您将:
for (auto & f : frames) /* auto-ranged for loop to output frames */
std::cout << "\nframe: " << f.get_frame() <<
" particles: " << f.get_nparticles() << "\n\n" <<
f << '\n';
将#include <iostream>
#include <vector>
#include <fstream>
struct Particle {
long double x,y,z;
char tab ='\t';
char newline = '\n';
char atom ;
friend std::istream& operator>>(std::istream& in, Particle &xyz) {
in >> xyz.atom >> xyz.x >> xyz.y >> xyz.z;
return in;
}
friend std::ostream& operator<<(std::ostream& out, Particle &xyz) {
out << xyz.x << xyz.tab << xyz.y << xyz.tab << xyz.z << xyz.newline;
return out;
}
};
class XYZ_frame_read
{
int curr_frame;
int num_particles;
std::vector<Particle> coordinates_t;
public:
friend std::istream& operator>>(std::istream& in, XYZ_frame_read &traj)
{
/* validate that num_particles and curr_frame read */
if (in >> traj.num_particles >> traj.curr_frame) {
int n = traj.num_particles; /* set number of particles to read */
Particle p;
while (n-- && (in >> p)) /* read that number of particles */
traj.coordinates_t.push_back(p);
}
return in;
}
friend std::ostream& operator<<(std::ostream& out, XYZ_frame_read &traj) {
for(int i = 0; i< traj.num_particles ;i ++)
out << traj.coordinates_t.at(i) ;
return out;
}
int get_frame(void) { return curr_frame; }
int get_nparticles (void) { return num_particles; }
int getpsize(void) { return coordinates_t.size(); }
};
int main(int argc, char *argv[]) {
std::ifstream in(argv[1]);
std::vector<XYZ_frame_read> frames; /* vector of frames (NO new!) */
for (;;) { /* continual loop while good input */
XYZ_frame_read tmp; /* temp XYZ_frame_read for read */
if ((in >> tmp)) /* if read is good */
frames.push_back(tmp); /* add it to vector of frames */
else
break; /* otherwise -- bail */
}
for (auto & f : frames) /* auto-ranged for loop to output frames */
std::cout << "\nframe: " << f.get_frame() <<
" particles: " << f.get_nparticles() << "\n\n" <<
f << '\n';
return 0;
(void)argc; /* suppress -Wunused warning */
}
用于vector
而不是class XYZ_frame_read
进行分配有许多优点。自动内存管理只是冰山一角。
示例输入文件
使用示例输入:
new
使用/输出示例
只需提供文件名,$ cat particles.txt
5
0
C 1.23 2.33 4.56
C 1.23 2.33 5.56
C 1.23 2.33 6.56
C 1.23 2.33 7.56
C 1.23 2.33 8.56
5
1
C 2.23 2.33 4.56
C 2.23 3.33 5.56
C 2.23 4.33 6.56
C 2.23 5.33 7.56
C 2.23 6.33 8.56
就会自动填充,无论数据文件中有多少帧(不超过虚拟内存的限制)
std::vector<XYZ_frame_read> frames