How do i find a string and delete it with a following string from a file in C++? - c++

How do i find a string in a file? In my code, i want to find the name of a person in the file. and do the actions in the comments. Here is my code:
int main(){
size_t found;
ofstream myfile;
cout << "Enter the name you wish to delete." << endl;
getline(cin, name);
myfile.open("database.dat");
found=myfile.find(name);
if (found!=string::npos){
number = myfile.tellg();
/*Delete current line and next line*/
}
}

Do you want to modify the file, or simply skip those two lines while reading?
Actually, the solution is the same for both, because removing data from the middle of the file requires reading everything after that and rewriting it with an offset (just like removing an element from the middle of an array).
So, read the entire file into memory except for any lines you determine need to be deleted (just skip those). After that, write the surviving lines back to disk. It's probably a good idea to use a temporary file which gets moved to the original name as a final step, so that data isn't destroyed if your process is aborted.

Related

Fstream getline() only reading from the very first line of text file, ignoring every other line

I am working on a coding project where I sort and organize data from a text file, and I cannot get the getline() function to read past the first line.
The idea is to capture the entire line, split it into 3 sections, assign it to an object, then move on. I can do everything except get getline() to work properly, here is the snippet of code I am having trouble with:
ifstream fin;
fin.open("textFile.txt");
while (!fin.eof()) // while loop to grab lines until the end of file is reached
{
getline(fin, line);
fin >> first >> last >> pace; // assigning the data to their respective variables
ClassObject obj(first, last, pace); // creating an object with those variables
ClassVector.push_back(obj); // assignment object to vector
}
This has been the closest I have gotten to reading every line while also sorting the data into a vector, but as I mentioned before, getline() will read line 1, and skip the rest of the file (1000 lines).
what you can do is rather than using !fin.eof(). i prefer to use something similar to this:
ifstream file ( fileName.c_str() );
while (file >> first >> last >> pace ) // assuming the file is delimited with spaces
{
// Do whatever you want with first, last, and pace
}
The "While loop" will keep reading the next line until we reach the end of the file.
If the lengths of first, last, pace are constant, you can also just get the contents of the line (in a string variable) and use substring on it, but this only works in the specific case that the lengths are constant throughout the entire file.

unable to read and write using same fstream object in c++

I'm trying to use same fstream object for first write the file and after that read the file.
when I'm using below code then the codes of writing the file is working but I'm getting junk output instead of texts which written in the file.
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main() {
fstream file;
file.open("test.txt",ios::in|ios::out| ios::trunc);
if (!file) {
cout << "Error";
}
else {
cout << "success";
file <<"\n\n1st Line\n 2nd line \n 3rd line\n";
string filecontent;
while (file.good()) {
getline(file, filecontent);
cout << filecontent << endl;
}
}
return 0;
}
Output
This code has two separate problems. The first (which others have already pointed out to at least some degree) is that your loop isn't detecting the end of the file correctly. In fact, almost any time you use while (!file.eof()) or while (file.good()), it's going to be a mistake--it won't detect end of file at the right time, so (for example) when you reach the end of the file, you won't detect it at the right time, and you'll see the last item in the file appear to be read twice before the loop exits.
In addition to that, however, you have a problem in that you're writing to the file, then immediately trying to read. That's simply not allowed--you want to do a seek any time you switch between reading and writing.
In this case, you have a bit of a further problem. Since you've just written data into the file, your file's current position is at the end of the file. So even if you could just start reading without seeking, you'd start reading from the end of the file. That, of course, would immediately fail.
So you also really need to seek back to the beginning of the file to be able to read it back in.
So, the big changes here are adding a line like: file.seekg(0); after you finish writing, but before you start to try to read that data back in, and then changing your reading loop to something like:
while (getline(file, filecontent)) {
cout << filecontent << endl;
}
One last point: although it's not going to make a big difference in this case, I'd advise using "\n" instead of std::endl. std::endl writes a new-line and flushes the file buffer. When you're writing to the screen it won't make any real difference, but when writing to a normal file flushing the buffer unnecessarily can and will slow your code substantially (10x slower is pretty common).

Difference between CSV files which makes different outcome using getline()

I'm writing a function which reads a CSV file using getline() and converts data to the vector of vectors. To test it I've tried to read two files with the same delimiter: one imported from the internet and second exported from R datasets. The first few lines of each looks like:
File1.csv
User ID,Category 1,Category 2,Category 3,Category 4,Category 5,Category 6,Category 7,Category 8,Category 9,Category 10
User 1,0.93,1.8,2.29,0.62,0.8,2.42,3.19,2.79,1.82,2.42
User 2,1.02,2.2,2.66,0.64,1.42,3.18,3.21,2.63,1.86,2.32
User 3,1.22,0.8,0.54,0.53,0.24,1.54,3.18,2.8,1.31,2.5
User 4,0.45,1.8,0.29,0.57,0.46,1.52,3.18,2.96,1.57,2.86
File2.csv
"","Sepal.Length","Sepal.Width","Petal.Length","Petal.Width"
"1",5.1,3.5,1.4,0.2
"2",4.9,3,1.4,0.2
"3",4.7,3.2,1.3,0.2
"4",4.6,3.1,1.5,0.2
However getline() works only for the first one. In second case it simply returns white space. The function performs similar even if I copy single lines from one file to another (of course adding or removing additional colums) -- the rows from file1 will be always properly read while those from file2 never. I've even tried removing " chars, but without much improvement. However switching from comas to '\t' solves the problem.
I'm curious what's the difference between those two files that makes such different outcome?
The source code of my function:
vector<vector<string>> readData(string fileName,int firstLine,char delimeter){
//Open data file
fstream fin;
fin.open(fileName, ios::in);
//Data stored in 2d vector of strings
vector<vector<string>> data;
vector<string> row;
string line,word,temp;
//Read data
int i=0;
while(fin>>temp){
row.clear();
//Read line and store in 'line'
getline(fin,line);
//Don't read first n lines
if (i<firstLine){
i++;
continue;
}
cout<<line<<endl;
//Break words
stringstream s(line);
//Read every column and store in in 'word;
while(getline(s,word,delimeter)){
row.push_back(word);
}
//Append row to the data vector
data.push_back(row);
}
//Close file
fin.close();
return data;
}
The problem is here:
while(fin>>temp){
row.clear();
//Read line and store in 'line'
getline(fin,line);
fin >> temp reads everything till the first space or newline. It is not clear why you do that as only with getline(fin,line) you then try to read the full line and you are not using temp. In the first file fin>>temp consumes only "User", in the second file it consumes the full line, because there are no spaces.
If you look at the read data from the first file you will also notice that the first part of each line is missing.
Tip: Use more meaningful names for your variables. I didn't manage to fully understand your logic, because variables named s and the presence of row and line at the same time causes me headaces.

How to DELETE a line(s) in C++?

I am new to file-handling...
I am writing a program that saves data in text-files in the following format:
3740541120991
Syed Waqas Ali
Rawalpindi
Lahore
12-12-2012
23:24
1
1
(Sorry for the bad alignment, it's NOT a part of the program)
Now I'm writing a delete function for the program that would delete a record.
So far this is my code:
void masterSystem::cancelReservation()
{
string line;
string searchfor = "3740541120991";
int i=0;
ifstream myfile("records.txt");
while (getline(myfile, line))
{
cout << line << endl;
if (line==searchfor)
{
// DELETE THIS + THE NEXT 8 LINES
}
}
}
I've done a bit of research and have found out that there is no easy way to access the line of a text file so we have to create another text file.
But the problem arises that how do I COPY the records/data before the record being deleted into the NEW text file?
Open the input file; read one line at a time from the input file. If you decide to want to keep that line, write it to the output file. On the other hand, if you want to 'delete' that line, don't write it to the output file.
You could have a record per line and make even more easy for example:
3740541120991|Syed Waqas Ali|Rawalpindi|Lahore|12-12-2012|23:24|1|1
and the | character saparating each field. This is a well known technic knows as CSV (Comma separated Values)
This way you don't have to worry about reading consecutive lines for erase a record and add a record access the file only once.
So your code becoms into:
void masterSystem::cancelReservation()
{
string line;
string searchfor = "3740541120991";
ifstream myfile("records.txt");
while (getline(myfile, line))
{
// Here each line is a record
// You only hace to decide if you will copy
// this line to the ouput file or not.
}
}
Don't think only about removing a record, there are others operations you will need to do against this file save a new record, read into memory and search.
Think a moment about search, and having your current desing in mind, try to answer this: How many reservations exists for date 12-12-2012 and past 12:00 AM?
In your code you have to access the file 8 times per record even if the other data is irrelevant to the question. But, if you have each record in a line you only have to access file 1 time per record.
With a few reservations the diference is near 0, but it grows exponentially (n^8).

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.