update records in file (c++) - c++

I wanted to ask how can I append strings to the end of fixed number of lines (fixed position). I am trying and searching books and websites for my answer but I couldn't find what I am doing wrong.
My structure :
const int numberofdays=150 ;
const int numberofstudents=2;
struct students
{
char attendance[numberofdays]; int rollno;
char fullname[50],fathersname[50];
}
Creating a text file
ofstream datafile("data.txt", ios::out );
Then I take input from the user and save it to the file.
How I save my data to text files :
datafile <<attendance <<endl<< rollno <<endl<<
fullname <<endl<< fathersname <<endl ;
How it looks like in text files :
p // p for present - 1st line
1 // roll number
Monte Cristo // full name
Black Michael // Fathers name
a // a for absent - 5th line
2 // roll number
Johnson // full name
Nikolas // Fathers name
How I try to update the file. (updating attendance for everyday)
datafile.open("data.txt", ios::ate | ios::out | ios::in);
if (!datafile)
{
cerr <<"File couldn't be opened";
exit (1);
}
for (int i=1 ; i<=numberofstudents ; i++)
{
long int offset = ( (i-1) * sizeof(students) );
system("cls");
cout <<"\t\tPresent : p \n\t\t Absent : a"<<endl;
cout <<"\nRoll #"<<i<<" : ";
cin >> ch1;
if (ch1 != 'p')
ch1 = 'a';
datafile.seekp(offset);
datafile <<ch1;
datafile.seekg(0);
}
I just want to add (append) characters 'p' or 'a' to the first or fifth line, I tried every possible way but I am unable to do it.

What you are doing is fairly common, but as you say it is inefficient if the size of data grows. Two solutions are to have fixed size records and index files.
For fixed-size records, in the file write the exact bytes of your data structure rather than a variable length text. This would mean you don't have a text file any more, but a binary file. You can then calculate the position to seek to easily.
To create an index file, write two files at once, one your variable size record file, and the other write a binary value with either the offset of the data from the start of the file. Since the index is a fixed size, you can seek to the index, read it, then seek to the position in the data file. If the new record will fit, you can update it in place, otherwise fill in with blanks and put the updated record at the end of the data file, then update the index file to point to the new location. This is basically how early PC databases worked.
Fixed size records are rather inflexible, and by the time you've implemented the index file system and tested it, now-a-days you probably would use a in-process database instead.

I came up with my own (easy & inefficient) logic to copy every line (except the line I want to update) to the another file.
I made my text file to be created like this :
=p // p for present - 1st line
1 // roll number
Monte Cristo // full name
Black Michael // Fathers name
=a // a for absent - 5th line
2 // roll number
Johnson // full name
Nikolas // Fathers name
Then I made the following code to update 1st and 5th line :
ifstream datafile("data.txt", ios ::in);
ofstream tempfile("temp.txt" , ios ::out);
string data, ch1;
while (getline(datafile,data))
{
if (data[0]=='=')
{
system("cls");
cout <<"\t\tPresent : p\n\t\tAbsent : a"<<endl;
cout <<"\nRoll #"<<i<<" : ";
cin >> ch1;
++i;
if (ch1 != "p")
ch1 = "a";
data=data+ch1; // Appending (updating) lines.
}
tempfile <<data <<endl; // If it was 1st or 5th line, it got updated
}
datafile.close(); tempfile.close();
remove("data.txt"); rename("temp.txt" , "data.txt");
But as you can see, this logic is inefficient. I will still wait for someone to inform me if I could somehow move my file pointer to exact location (1st and 5th line) and update them.
Cheers!

Related

Store Input from Text File into Arrays or Variables?

My Problem:
I am very new to new to programming and trying to write a program in C++, I have a text file. *In the text file is stored is a Students Name, Grade, and Grade Letter. I want them stored as different types in arrays *
I want to store them individually in an array....
ie text file would look like this:
Jill Hamming A 96
Steven Jenning A 94
Tim Sutton B 89
Dillon Crass C 76
Sammy Salsa D 54
Karen Poulk D 49
I would like to store all the First names in one array, last names in another etc. So on and so on.
These arrays will later be assigned to object for the student. There maybe up to 500 students.
So the question:
How to store input from a text document into an array instead of using 500 variables.
ie. Here is my attempt.
int main()
{
/// the input is all different types, strings, ints and chars
string my_First_Name[500], my_Last_Name[500];
int my_grade[500];
char my_letter[500];
ifstream myfile("input.txt");
if (myfile.is_open()){
for (int i = 0; i < 500; i++) {
myfile >> my_First_Name[i] >> my_Last_Name[i] >> my_grade[i] >> my_letter[i];
}
// much later and irrelevent part but just showing because this is what I want to do. where Student Class exsists somewhere else. yet to be programmed.
Student myStudent [500];
myStudent[i].Grades = my_grade[i];
myStudent[i].LetterGrade = my_letter[i];
}
myfile.close();
//Exit
system("pause");
return 0;
}
When I went to print out what I had. I had all negative and weird numbers which means it was not initialized. Where did I go wrong?
When you have multiple arrays of the same size, it is usually as sign of poor design.
The rule of thumb is to have a record (or line of data) represented by a class or structure:
struct Record
{
string first_name;
string last_name;
int grade_value; // Can this go negative?
string grade_text;
};
If you know you are going to have 500, you can create an array for the data:
#define ARRAY_CAPACITY (500)
Record grades[ARRAY_CAPACITY];
This not a great solution, because you waste space if there are less than 500 and perform buffer overrun if you read more than 500.
Thus a better solution is to use std::vector, which allows you to append records as you read them. The std::vector will expand as necessary to contain the records. With an array, you would have to allocate a new array, copy old records to new array, then delete the old array.
Also, a good solution will include methods, inside Record, to read the data members from an input stream. Research "overloading stream extraction operator".
You input loop should look something like:
Record r;
while (input_file >> r)
{
student_grades.push_back(r);
}
You can find this information by searching stackoverflow. A good beginning search is "stackoverflow c++ read file space separated" or "comma separated" or "stackoverflow c++ read file structure".
Reading a record
You could expand the loop to something like this:
std::vector<Record> student_grades;
Record r;
while (input >> r.first_name >> r.last_name >> r.grade_value >> r.grade_text)
{
student_grades.push_back(r);
}
If you are allergic or limited to arrays, you will need to use a counter with the array.
#define MAXIMUM_RECORDS (500)
Record r;
Record grade_book[MAXIMUM_RECORDS];
unsigned int record_count = 0U;
while (input >> r.first_name >> r.last_name >> r.grade_value >> r.grade_text)
{
grade_book[record_count] = r;
++record_count;
if (record_count >= MAXIMUM_RECORDS)
{
break;
}
}
A for loop is not used because we don't know how many records are in the file, only a maximum that the program will read. If the file has 600 records, only 500 will be read.

cash reg loading individual words from each line into the different struct members

I have this homework assignment that has me a little lost. I have been working on this assignment writing my code, erasing, rewrite, repeat etc. Here are the instructions:
Step (1)
Associated with this assignment is a data file called prices.txt. It contains details of the prices for items in a
grocery store. The first column is the barcode for the item (http://en.wikipedia.org/wiki/Barcode) the
second column, starting in position 11, is the product name, and the third column, starting in position 37 is
the product price.
Write a function with the signature int loadData() which prompts the user for the location of the data file
on disk and then loads the data from the file into an array of elements. Each element of the array should be
a struct declared as follows:
struct Item {
string code;
string name;
double price;
};
The array itself should be called items and should be declared at file scope as follows:
const int MAX_ITEMS = 100;
Item items[MAX_ITEMS];
Notice that the array has size 100, so you can assume the number of items in the data file is less than 100.
Therefore, when loadData has finished loading the data into the array some elements in the array will be unused. The function loadData returns the number of items actually loaded into the array.
I am unsure on how to attempt the function described in the instructions. My code:
int loadData () {
string inputFileName;
ifstream inputFile;
int numOfItems = 0;
cout << "Please input the name of the backup file: ";
cin >> inputFileName; //read user input for the location of the
//backup file
inputFile.open(inputFileName.c_str()); //open specified document
if (!inputFile.is_open()) { //If the file does not open the errormsg
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
//Not sure where to start. I know I need to get each element from
//each newline.
return numOfItems;
}
I wanted to figure this out on my own but that isn't gonna happen. So if I could just get some hints or even suggested pools of knowledge that would guide me or even give me an idea of where to start.
addition: input file:
10001 Apples (bunch) 4.59
10002 Bananas (bunch) 4.99
10003 Pears (bunch) 5.49
20001 White bread (loaf) 2.69
20002 Brown bread (loaf) 2.89
20003 English Muffins (bag) 3.99
30001 Sugar (5 lb bag) 3.99
30002 Tea (box) 4.29
30003 Folger's Coffee (Can) 13.29
This is the entire input file.
Since the input file seems to be using fixed-width columns, it's actually very easy to extract the fields. Just read one line at a time, and for each line get each element as a sub-string, and put into the structure members. And there are functions to convert strings to floating-point values as well.
Don't worry about the possible leading or trailing spaces, there are ways of trimming that.

Input object data from a file in a specific format, add/edit that data, and then output it to the file again

so this is my first time posting a question here so please bear with me. I am studying computer science for my bachelors, and I would like some help. We have created various Classes that are all part of a Roster Management System. I have all the classes set up and such, and I can figure out how to store everything in a dynamically allocated array later on, for the time being I am having a difficult time just reading the data needed from a file.
The format for the text file is as follows:
course1-name | course1-code | number-credits | professor-name
student1 first name | student1 last name|credits|gpa|mm/dd/yyyy|mm/dd/yyyy
student2 first name | student2 last name|credits|gpa|mm/dd/yyyy|mm/dd/yyyy
end_roster|
course2-name | course2-code | number-credits | professor-name
student1 first name | student1 last name|credits|gpa|mm/dd/yyyy|mm/dd/yyyy
end_roster|
As you can see, the rosters only have four data fields, course name, course code, number of credits and the professors name.
Students have 6 fields, 7 if you include the end_roster marker (the end_roster marker is literally just that, not a bool value or anything.
Anyway, I cant seem to figure out how to read this input properly. I can read it all in and tokenize it, but then I don't know how to append each "section" to its correct class. This happens to give me each "token" (not 100% clear what that is, but it seems to append each set of characters into a string). I do not know how to assign it into their proper places from this point forward though.
ifstream myroster("rosters.txt");
while( ! myroster.eof() )
{
getline(myroster, line);
cout << line << endl << endl;
char c[line.length() + 1];
strcpy (c, line.c_str());
char * p = strtok(c, "|");
while (p != 0)
{
cout << p << endl;
p = strtok(NULL, "|");
counter++;
}
}
myroster.close();
I've also tried the following;
ifstream myroster("rosters.txt");
while (!myroster.eof())
{
getline(myroster, line, '|');
counter++;
}
Both methods had some form of counter implementation (my first attempt). For example; if counter == 4 it'll be appended to roster, or counter == 6 and its students, but nothing worked (I realized the flaw later on)
The reason I don't just hardcode the program to implement line one for roster1 information, line 2 for student 1, line 3 for student 2, and etc is because the data needs to be edited in the program, and one of the options is to add students/remove them and add rosters/remove them, after which the file needs to be updated again, and then read in again after.
Can anyone shed some light on this?

search for specific row c++ tab delmited

AccountNumber Type Amount
15 checking 52.42
23 savings 51.51
11 checking 12.21
is my tab delmited file
i would like to be able to search for rows by the account number. say if i put in 23, i want to get that specific row. how would id do that?
also more advance, if i wanted to change a specific value, say amount 51.51 in account 23. how do i fetch that value and replace it with a new value?
so far im just reading in row by row
string line;
ifstream is("account.txt");
if (is.is_open())
{
while (std::getline(is, line)) // read one line at a time
{
string value;
string parseline;
std::istringstream iss(line);
getline(line, parseline);
cout << parseline << endl; // do something with the value
while (iss >> value) // read one value at at time from the line
{
//cout << line << " "; // do something with the value
}
}
is.close();
}
else
cout << "File cant be opened" << endl;
return 0;
Given that each line is of variable length there is no way to index to particular row without first parsing the entire file.
But I suspect your program will want to manipulate random rows and columns. So I'd start by parsing out the entire file. Put each row into its own data structure in an array, then index that row in the array.
You can use "strtok" to split the input up into rows, and then strtok again to split each row into fields.
If I were to do this, I would first write a few functions that parse the entire file and store the data in an appropriate data structure (such as an array or std::map). Then I would use the data structure for the required operations (such as searching or editing). Finally, I would write the data structure back to a file if there are any modifications.

read in values and store in list in c++

i have a text file with data like the following:
name
weight
groupcode
name
weight
groupcode
name
weight
groupcode
now i want write the data of all persons into a output file till the maximum weight of 10000 kg is reached.
currently i have this:
void loadData(){
ifstream readFile( "inFile.txt" );
if( !readFile.is_open() )
{
cout << "Cannot open file" << endl;
}
else
{
cout << "Open file" << endl;
}
char row[30]; // max length of a value
while(readFile.getline (row, 50))
{
cout << row << endl;
// how can i store the data into a list and also calculating the total weight?
}
readFile.close();
}
i work with visual studio 2010 professional!
because i am a c++ beginner there could be is a better way! i am open for any idea's and suggestions
thanks in advance!
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits>
struct entry
{
entry()
: weight()
{ }
std::string name;
int weight; // kg
std::string group_code;
};
// content of data.txt
// (without leading space)
//
// John
// 80
// Wrestler
//
// Joe
// 75
// Cowboy
int main()
{
std::ifstream stream("data.txt");
if (stream)
{
std::vector<entry> entries;
const int limit_total_weight = 10000; // kg
int total_weight = 0; // kg
entry current;
while (std::getline(stream, current.name) &&
stream >> current.weight &&
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n') && // skip the rest of the line containing the weight
std::getline(stream, current.group_code))
{
entries.push_back(current);
total_weight += current.weight;
if (total_weight > limit_total_weight)
{
break;
}
// ignore empty line
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
else
{
std::cerr << "could not open the file" << std::endl;
}
}
Edit: Since you wannt to write the entries to a file, just stream out the entries instead of storing them in the vector. And of course you could overload the operator >> and operator << for the entry type.
Well here's a clue. Do you see the mismatch between your code and your problem description? In your problem description you have the data in groups of four lines, name, weight, groupcode, and a blank line. But in your code you only read one line each time round your loop, you should read four lines each time round your loop. So something like this
char name[30];
char weight[30];
char groupcode[30];
char blank[30];
while (readFile.getline (name, 30) &&
readFile.getline (weight, 30) &&
readFile.getline (groupcode, 30) &&
readFile.getline (blank, 30))
{
// now do something with name, weight and groupcode
}
Not perfect by a long way, but hopefully will get you started on the right track. Remember the structure of your code should match the structure of your problem description.
Have two file pointers, try reading input file and keep writing to o/p file. Meanwhile have a counter and keep incrementing with weight. When weight >= 10k, break the loop. By then you will have required data in o/p file.
Use this link for list of I/O APIs:
http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx
If you want to struggle through things to build a working program on your own, read this. If you'd rather learn by example and study a strong example of C++ input/output, I'd definitely suggest poring over Simon's code.
First things first: You created a row buffer with 30 characters when you wrote, "char row[30];"
In the next line, you should change the readFile.getline(row, 50) call to readFile.getline(row, 30). Otherwise, it will try to read in 50 characters, and if someone has a name longer than 30, the memory past the buffer will become corrupted. So, that's a no-no. ;)
If you want to learn C++, I would strongly suggest that you use the standard library for I/O rather than the Microsoft-specific libraries that rplusg suggested. You're on the right track with ifstream and getline. If you want to learn pure C++, Simon has the right idea in his comment about switching out the character array for an std::string.
Anyway, john gave good advice about structuring your program around the problem description. As he said, you will want to read four lines with every iteration of the loop. When you read the weight line, you will want to find a way to get numerical output from it (if you're sticking with the character array, try http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/, or try http://www.cplusplus.com/reference/clibrary/cstdlib/atof/ for non-whole numbers). Then you can add that to a running weight total. Each iteration, output data to a file as required, and once your weight total >= 10000, that's when you know to break out of the loop.
However, you might not want to use getline inside of your while condition at all: Since you have to use getline four times each loop iteration, you would either have to use something similar to Simon's code or store your results in four separate buffers if you did it that way (otherwise, you won't have time to read the weight and print out the line before the next line is read in!).
Instead, you can also structure the loop to be while(total <= 10000) or something similar. In that case, you can use four sets of if(readFile.getline(row, 30)) inside of the loop, and you'll be able to read in the weight and print things out in between each set. The loop will end automatically after the iteration that pushes the total weight over 10000...but you should also break out of it if you reach the end of the file, or you'll be stuck in a loop for all eternity. :p
Good luck!