I have created a roster program that accepts user input to create/write/delete information into and out of a specified text file. My issue now becomes wanting to create a lasting text file that isn't overwritten every time I re-run the program and am not sure if using fstream or a combination of of/ifstream is better practice, or if there is maybe a third option I missed when checking the reference docs.
Right now I am simply using: std::ofstream outfile("roster.txt"); which works, until I kill and re-run the program to which my text file is now wiped clean.
check out the append flag. it writes to the end of an existing file.
http://www.cplusplus.com/doc/tutorial/files/
example here.
std::ofstream outfile("roster.txt" , ios::app)
I am a beginner C++ programmer.
I want to create a binary file, that is uncleared with the previous information that was in it. This is easy to do with RAM, simply by making an array, but how do I do this on a hard drive?
How do I create a uncleared file?
In other words how do I retrieve data that was not "cleared" but just marked "empty".
However, if the OS does not allow it, can I launch linux from USB and run my software?
To keep the content of a file to be written on, you can open a file in append mode with:
[ofstream ofs ("filename", ios::binary | ios::app);][1]
All output operations append at the end of the file. Alternatively, you could also use ios::ate so that the output position starts at the end of the file (but afterwards it's up to you).
With the usual read operations you can retrieve preexisting content, by first positionning yourself using seekp().
I want to open a file, read the data, and after a calculation, write over the data that I read, but I don't want to close it and re-open it, because this will slow down my program as it does this over and over again and it does slow it down.
Essentially, I have a starting number, then I do some calculations and move on to the next number. Since I don't want to redo all these calculations, I have a file with the starting number in it and a file with the output list. I want to change the starting number so I'm not needlessly redoing calculations. If you need to see some of my code, just say so. Thanks guys/gals/variations thereof.
I'm using c++.
I think it would be better if you have the contents on memory, but anyway you can use seekp to change the pointer to the actual position in file
I believe what you are trying to achieve can be done using fstream the syntax is very similar to this:
std::fstream file;
file.open ("textfile.txt", std::fstream::in | std::fstream::out | std::fstream::app);
Here is a link to a better explanation http://www.cplusplus.com/reference/fstream/fstream/open/
Since I have reached the end of the file, the eof flag will be set. I need to clear that using (ifile is the fstream variable in this example) ifile.clear – then try seeking:
ifile.clear();
ifile.seekg(0, ios::beg);
I am trying to understand how basic I/O with files is handled in c++ or c. My aim is to read file line by line and send the lines across to a remote server. If the line is sent, I want to delete it from the file.
One way I tried was that I kept a count of the lines read and called an system() system call to delete the 'count' number of lines. I used the bash command: sed -i -e 1,'count'd filename.
After that I continued reading the file and surprisingly it worked as planned.
I have two questions:
Is this way reliable?
And why does this work at all, when while
reading the file I deleted a part of it and yet it works? What if I
did a seek to a previous position, what then?
Best,Digvijay
PS:
I would be glad if somebody could suggest a better way.
Also here is the code for the program I wrote:
#include<iostream>
#include<fstream>
#include<string>
#include<sstream>
#include<cstdlib>
int main(){
std::ifstream f;
std::string line;
std::stringstream ss;
int i=0;
f.open("in.txt");
if(f.is_open()){
while(getline(f,line)){
std::cout<<line<<std::endl;
i++;
if(i==2)break;
}
ss<<"sed -i -e 1,"<<i<<"d in.txt";
system(ss.str().c_str());
while(getline(f,line)){
std::cout<<line<<std::endl;
}
}
return 0;
}
Edit:
Firstly thanks for taking the time to write answers. But here is some extra information which I missed out on earlier. The files I am dealing with are log files. So they are constantly being appended with information from devices. The reason why I want to avoid creating a copy is, because the log file themselves are very big(at times) and plus this would help to keep the log file short. Since they would be divided into parts and archived on the server.
Solution
I have found the way to deal with the problem. Apparently Thomas is right, that sed does create a new file. So the old file remains as is. Using this, I can read n lines, call the system function, close the file pointer and open it again. I do this on small chunks of the log, repeatedly until it becomes small and hence efficient to deal with. The server while archives the logs in 1gb files.
However I have a new question, due to memory constraint, I need to know if it is possible to split a log file into two efficiently. (Which possibly would be another question on SO)
Most modern file systems don't support deleting lines at the beginning of the file, so doing so would be very inefficient.
The normal solution to your actual problem is to stop writing to your log file when it reaches some size, then start writing to a new file. The code that copies the files can delete a whole file once it has been written (this is an efficient operation).
sed writes a new version of the file, while the program keeps reading the same version that it opened. This is the usual behavior of Unix and Linux when a program writes a file that another program has open.
You can see this for yourself with this small C program:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
FILE *f = fopen("in.txt", "r");
while (1) {
rewind(f);
int lines = 0;
int c;
while ((c = getc(f)) != EOF)
if (c == '\n')
++lines;
printf("Number of lines in file: %d\n", lines);
}
return 0;
}
Run that program in one window, and then use sed in another window to edit the file. The number of lines printed by the program will stay the same, even if the file on disk has been edited, and this is because Unix keeps the old, open version, even if it is no longer accessible to other programs.
As to your first question, how reliable your solution is, as far as I can see it should be reliable, except with the usual caveats about the system crashing or running out of memory in the middle of an update, someone else accessing the file, and of course all the problems with the system call. It is not very efficient, though, and for large data sets you might want to do it differently.
sujin's comment about using a temporary file for the lines you want to keep seems reasonable. It would be both faster and safer. Keep the original file, so if the system crashes you'll still have your data, and wait until you have finished to rename the old file to "in.txt.bak", and then rename your temporary file to "in.txt".
First off, avoid use of system calls as much as you can (if possible, don't use it at all) as they create race conditions and other problems which drastically (and often) detrimentally affect the outcome of your program. This especially true if access to files are involved.
Given your problem, there are a number of ways to do this, each with its own caveats.
I'll cover three possible solutions:
1) If the file is small enough:
you can read in the entire thing in a data structure (vector, list, deque, etc.)
delete the original file
determine how many lines to read (and send off via server protocol)
then write the remaining lines as the name of the original file.
If you intend to parallelize your program later on, this may be a better solution, provided that the file is small. Note: small is a relative term, but is generally limited by how much memory you have available.
2) If the file is quite large or you're limited by memory constraints, you will have to get creative by using buffers. Once you've read a line and successfully sent it off via your program, you determine where the file pointer is and copy the remaining information until the end of the current file as a new file. Once done, close and delete the old file, then close and rename the new file the same name as the old file.
3) If your solution doesn't have to be in C++, you can use shell-scripting or (controversially) another language to get the job done.
1) No, it's not reliable.
2) The C++ runtime library reads your file in blocks (internally) which are then parceled out to your (higher level) input requests until the block(s) is(are) exhausted, forcing it to (internally) read more blocks from disk. Since one or more physical blocks are read in before you make any call to sed, it/they cannot be altered if sed happens to change that first part of the file.
To see your code fail, you would need to make the input file big enough that there are remaining blocks of the file that have not been read in (internally by the runtime library) before you call sed. By "fail" I mean your program would not see all the characters that were originally in the file before sed clobbered some lines.
As the other guys said, you have to make another file with the records you need after read the original file and then delete it. But in this application perhaps you will see more useful a fifo than a file. If you are on a *NIX platform check up about the makefifo statement from the console.
It is like a file with the singularity that after read a line it gets deleted.
My programming knowlege is very limited so please take this into account when reading this. I am using Visual C++ MFC and I am looking for a basic function that would overwrite the contents of a file but keep the file the same name. I am sure this is probably fairly simple however I can't seem to find anything online. Thanks in advance for any help.
You can use CFile::Open() there is flags to specify to open an existing file without truncating it. For example if you want to create the file if it not exists, or using the alreading existing without truncating you can use CFile::modeCreate|CFile::modeNoTruncate. You can then seet to the needed position by using CFile::Seek()
It's been a while since I've done any MFC work so I'll just give you the general standard on how to do this in C/C++. This will give you a direction on how to work with MFC.
When you're opening a file, you can choose an "open flag" that tells the file system how to open it. it can be "a" for append, "r" for read, "w" for write over (trunacte), and you can add "b" if it's a binary file.
so to do that just do:
FILE *fp = fopen("my_file.whatever", "wb");
if (fp)
{
//now write to
the file... ....
fclose(fp);
}