Multiple text files inside two loop - c++

I want to create some file inside two loops and fill out them without closing the file inside the first and second loop.
Here you can find what I mean of this question by looking at this part of a code, and it doesn't work ... of course, it creates 100 files but the problem is that each file just holds the last iteration of the first loop while I want each file to write the whole iteration of the first loop.
ofstream fout;
for(int t = 0; t < N; t++){
for(int e = 0; e < 100; e++){
fout.open("myfile_"+strcpp(e)+".txt");
fout << t << psi[e] << endl;
}
}
fout.close();
where the function strcpp(e) is given by
template <class T>
string strcpp(T value){
ostringstream out;
out << value;
return out.str();
}

Every time you call:
fout.open(...);
The whole contents of the file before opening it are erased. Since you open each file many times you are constantly erasing anything that you had written to it before you write the next line. This is why the last write of your outer for loop is the only thing in each file.
We can fix this by specifying we want to append to the file we are opening. std::ofstream::open() takes a second optional argument that specifies the mode. You can set the mode to append whatever you write in the file to the end of what is already in there instead of erasing the original file contents.
Ex:
fout.open(my_file_name, ios::app);
Although a better solution might be to just switch in your inner and outer for loop. Then you open each file before the start of the inner for loop, do all the writes to that one file, then close that file and move on to the next one. This way you don't have to open each file many, many times.

Related

How to print to file?

I'm need to print some info on a file ".txt".
I wrote on the program the link of the file I want to copy the info. The ".txt" file is empty.
Eclipse tells me that the code is without error. This is the part of code of the print on file:
void stampaVendute(string& vendute,int& n,Opere f[],char p[],int a){
cout<<"\nInserisci il file sul quale vuoi visualizzare le opere vendute: "<<endl;
getline(cin,vendute);
ofstream ofs;
ofs.open(vendute.c_str());
if(!ofs.good()){
cout<<"C'è qualche problema nell'apertura del file"<<endl;
return;
}
for(int i=0;i<n;i++){
if((!stricmp(p,f[i].N_C)) and a<=f[i].anno){
ofs<<"\nOPERA "<<(i+1)<<endl;
ofs<<"Codice: "<<f[i].codice<<";"<<endl;
ofs<<"Titolo: "<<f[i].titolo<<";"<<endl;
ofs<<"Autore: "<<f[i].N_C<<";"<<endl;
ofs<<"Anno: "<<f[i].anno<<";"<<endl;
ofs<<"Valore: "<<f[i].prezzo<<";"<<endl;
}
ofs.close();
}
cout<<"\nI DATI SONO STATI COPIATI CORRETTAMENTE SUL FILE!"<<endl;
}
If if((!stricmp(p,f[i].N_C)) and a<=f[i].anno){ fails the test then nothing is printed to the file. Add a line that unconditionally prints to the file after opening, to see if it works.
Print the file name to the user when the file is opened successfully.
If you are using Windows, you can use process monitor from SysInternals (now owned by Microsoft) to see what file is actually being opened.
ofs.open(vendute.c_str());
why are you using c_str here? You know that open takes a std::string normally! You are getting a pointer to the raw characters just to construct a new different string object, and forcing the compiler to re-count the number of characters (calling strlen() again).
You should write it as one line anyway. Initialize the variable when you define it:
ofstream ofs {vendute};
⧺SL.io.50 Don't use endl.
for(int i=0;i<n;i++){
... many uses of `f[i]` follows
You should be using a range-based for loop rather than subscripts, but the way you are passing the data (separate pointer to the first element and length) instead of simply passing a collection prevents that. This is not a good way to do things! See Standard Guidelines ⧺I.13 etc.
If you did need to go over the collection via subscripts, don't keep subscripting it over and over and over. Make a reference variable pointing to that spot:
for(int i=0;i<n;i++){
const auto& x = f[i];
... now use x over and over, not f[i]
here's your problem
Look where ofs.close(); is being called. The indentation of the code in the post is all messed up... it looks like this should be after the loop, before the final cout line. But what's that extra } coming from?
You are closing the file after the first iteration through the loop. If that case (i==0) did not print results, nothing will ever be shown.

trouble reading file into two objects repeatedly without an infinite loop

c++ beginner and first time poster here.
I'm reading a file consisting of a series of large numbers separated by semicolons.
I am trying to create a loop where the file is read into two objects (first number up to semicolon in first object, second number into second object), then print the two objects containing each number. After printing the first two, it should repeat with the next two numbers until the end of the file is reached.
I have been playing around with it a lot and can't get it to work. Two problems keep occurring:
Infinite loop
failure to read the number into an object
I currently have the operator >> overloaded as follows:
std::istream& operator>>(std::istream& fin, big& obj){
char temp[size];
char stop = ';';
fin.get(temp, size, stop);
//constructor converts temp to big
obj = big(temp);
return in;
}
I have the file opening correctly, and when I just use it on one object( in>>big1) it works properly and reads the first number.
But if I try to read into two objects (in>>big1>>big2) then only the first gets a number and second gets nothing (big1==1234 big2==0).
If I try to do this in a loop which is the end goal, then I just get an infinite loop of zero. This is the basic code I have right now of what I'm trying to do:
//file opens correctly
big big1, big2;
while (!fin.eof()){
//read two numbers from file seperated by semicolon
fin >> big1 >> big2;
std::cout << big1 << "\n";
std::cout << big2 << "\n";
//repeat until end of file reached
}
fin.close();
return 0;
How can I write this so it will work? I've been trying many ways of writing it and nothing works, but it has to be possible.
Please help me if you can!
also note I can't use predefined classes like std::vector or std::string

Write output to new files at every nth iteration

A fragment of my code is :
for (int iter = 0; iter < flags.total_iterations_; ++iter) {
if (iter%20==0) {
std::ofstream mf(flags.model_file_.c_str());
accum_model.AppendAsString(word_index_map, mf); }
else {
std::cout << "Model not created for "; }
std::cout << "Iteration " << iter << " ...\n";
So, I am trying to generate outputs from method accum_model at every 20th iteration. But, the problem is I have to write the output in new file everytime the 20th iteration is reached. Now, my output is being overwritten.
I execute this code with the help of a executible, which is as:
./lda --num_topics 15 --alpha 0.1 --beta 0.01 --training_data_file testdata/test_data.txt --model_file MF/lda_model.txt --burn_in_iterations 120 --total_iterations 150
The MF/lda_model.txt is the output file given. I am not understanding how to link the file that contains the code and this executible command as I would need 5 different new files (for 100 iterations - as data is written into a new file every 20th iteration).
I am new to coding and so far, I was coding in python. I tried till this loop, I am confused about how to create new files and get corresponding outputs. Please help! Thanks in advance.
Use std::stringstream, and build a new file name to open each time.
std::string uniquePathFileNamePostFix (int i) {
std::stringstream ss;
ss << '-' << i ;
return (ss.str());
}
The idea is to use the stringstream to create (or append or prepend) a unique modifier based on i. (or anything else convenient - I have used time stamps).
If I understand your question correctly, you are overwriting the ofstream instead of appending to it.
You'll want to specify the 'app' flag in the mode of the ofstream constructor:
std::ofstream mf(flags.model_file_.c_str(), std::ios_base::app);
If you need to start the output with an new, "empty" file, just leave out the mode (ofstream defaults to std::ios_base:out, whether you specify it or not): std::ofstream::ofstream
...and if you need a new output file (according to your OP), you need to change the file name in flags.model_file_.
I'm not sure that I understand your question correctly, but I think you want to output every 20th iteration in a new file. To do so, you just need to append the value of theiter to the name of the file or otherwise add a "dynamic" element to it.
The way to do it using only standard C++ is using stringstream:
std::stringstream file_name;
file_name << flags.model_file_ << iter;
result = file_name.str();

does fstream move to the next position after read in a binary integer (c++)

I am trying to read in a binary file and write in chunks to multiple output files. Say if there are 25 4byte numbers in total and chunk size is set to 20, the program will generate two output files one with 20 integers the other with 5. However if I have a input file with 40 integers, my program generates three files, first 2 files both have 20 numbers, however the third file has one number which is the last one from the input file and it is already included in the second output file. How do I force the read position to move forward every time reading a number?
ifstream fin("in.txt", ios::in | ios::binary);
if(fin.is_open())
{
while(!fin.eof()){
//set file name for each output file
fname[0] = 0;
strcpy(fname, "binary_chunk");
index[0] = 0;
sprintf(index, "%d", fcount);
strcat(fname, index);
// open output file to write
fout.open(fname);
for(i = 0; i < chunk; i++)
{
fin.read((char *)(&num), INT_SIZE);
fout << num << "\n";
if(fin.eof())
{
fout.close();
fin.close();
return;
}
}
fcount ++;
fout.close();
}
fout.close();
}
The problem is most likely your use of while (!fin.eof()). The eofbit flag is not set until after you have tried to read from beyond the end of the file. This means that the loop will loop one extra time without you noticing.
Instead you should remember that all input operations returns the stream object, and that stream objects can be used as boolean conditions. That means you can do like this:
while (fin.read(...))
This is safe from the problems with looping while !fin.eof().
And to answer your question in the title: Yes, the file position is moved when you successfully read anything. If you read X bytes, the read-position will be moved forward X bytes as well.

C++ Reading file using while loop, start at line "x"

I've been stuck on this issue for a while. What I have here is a loop that will read a text file containing file names. The loop reads these lines one by one, and sets it into memory via the variable sFileName. sFileName is later called upon to load an image, and the program does this one by one as the loop loads it. The user then selects a tag for the image and loads the next one. The tag and the image file name are exported into another text file, named imgresults.txt. Now, the text file with the file names is a few thousand lines. So, in the case that the user has to exit the program and tries to continue later, the loop restarts, instead of leaving off at the point when the program was closed.
I am trying to find a way to have the loop start at that point. So far, I decided to use getline() to count how many lines are currently in imgresults.txt, as that will give the number of images that have already been run through the program. This number is stored in the variable "x". I've been doing a lot of research, but I just cannot find how to set a condition for the while loop to begin at line "x". Do you guys have any suggestions? Also, if you need any clarifications, please ask. I only included the code regarding the loop, as the code for loading the image and such is perfect fine.
int _tmain(int argc, _TCHAR* argv[])
{
int value = 0;
int nCounter = 0;
FILE* fIn = NULL;
char * sLine = new char[MAX_FILENAME_SIZE];
char * sFileName = new char [MAX_FILENAME_SIZE];
char * s = new char [MAX_FILENAME_SIZE];
#define ImgListFileName "path"
#define ImgRepository "path"
if ((fIn = fopen(ImgListFileName,"rt"))==NULL)
{
printf("Failed to open file: %s\n",ImgListFileName);
return nCounter;
}
ifstream imgresults;
imgresults.open ("imgresults.txt");
int x=0;
string line;
while(!imgresults.eof()) {
getline (imgresults, line);
x++;
}
srand (time(NULL));
cout << x;
while(!feof(fIn)){
memset(sLine,0,MAX_FILENAME_SIZE*sizeof(char));
memset(sFileName,0,MAX_FILENAME_SIZE*sizeof(char));
memset(s,0,MAX_FILENAME_SIZE*sizeof(char));
fgets(sLine,MAX_FILENAME_SIZE,fIn);
strncpy(s,sLine,65);
strcat(sLine,"\0");
strcat(sFileName,s);
printf (sFileName);
nCounter++;
}
Thanks in advance!
If you really want to use imgresults.txt as the information on where you should start from the input file, then the best you can do is to have a while loop to read x lines from the input file just before the while loop where you read the input file.
while (x--) {
fgets(sLine, MAX_FILENAME_SIZE, fIn);
}
Better solution would probably be to write state of processing to another file so that you would not have to read input file line by line, but you could immediately seek to a known offset in the file.
Use ifstream::tellg to retrieve and store the current position of the file when the programm was closed.
Use ifstream::seekg to restore that position when the porgramm restarts.
Before you read each line, save the current offsets in your input and output file to a separate file, seeking back to the beginning and overwriting the existing data each time.
When/if you restart, read the offsets from that file, seek to those points, and start working from there.
You can just read lines in parallel from both files and stop when you reach the end of results file. When the loop ends, you have already discarded the file names that were already processed.
ifstream results("results.txt");
ifstream names("names.txt");
if (results && names) {
std::string temp1, temp2;
while (getline(results, temp1) && getline(names, temp2)) ; /* do nothing */
}
if (names) {
// process the rest
}
Not the most efficient solution, but it saves you the hassle of saving offsets. Just make sure that before the very first processing the results file is completely empty (or doesn't exist at all), otherwise this code will skip the first line of names file.