having issues reading in files within a folder C++ - c++

I am currently working on a project that requires the assessment of mystery text files, and cross referencing them with signatures that are provided to me.
one issue I am facing is that we have gone over reading in files from a folder within the projects folder. (I'm using Visual Studios 2010)
I am provided with a simple 'data.txt' file, that contains an integer representing the number of file names of signatures; followed by that many signatures, then another integer representing the number of mystery texts; followed by that many mystery texts.
my question is, how does one read in a file, from a path given to them within another text document?
the 'data.txt' file is as follows:
13
signatures/agatha.christi.stats
signatures/alexandre.dumas.stats
signatures/brothers.grim.stats
signatures/charles.dickens.stats
signatures/douglas.adams.stats
signatures/emily.bronte.stats
signatures/fyodor.dostoevsky.stats
signatures/james.joyce.stats
signatures/jane.austen.stats
signatures/lewis.caroll.stats
signatures/mark.twain.stats
signatures/sir.arthur.conan.doyle.stats
signatures/william.shakespeare.stats
5
documents/mystery1.txt
documents/mystery2.txt
documents/mystery3.txt
documents/mystery4.txt
documents/mystery5.txt
one of the signature files is as follows(don't ask why my prof decided to use .stats, because I have no clue):
agatha christie
4.40212537354
0.103719383127
0.0534892315963
1
0.0836888743
1.90662947161
I cannot change the files, nor can I change the area in which they are saved.
I can easily read in the 'data.txt' file but cannot seem to find the signature files at all.
any help would be appreciated.
once I read in the signatures, I plan on saving them as structs in an array so I can reference them later in the project to compare them to the signatures of the mystery texts.
this program is using namespace std, if that matters to anyone...

Example as reading doubles.
File *file;
file = std::fopen(filename.c_str(), "r+b");
std::fread(&/*variableName*/, sizeof(double), 1, file);
Is this what you're looking for?

I assume your directory structure is as follows:
the_program
data.txt
signatures/...
documents/...
Then it should be straightforward to read the files:
std::ifstream in("data.txt");
std::vector<std::string> files;
int num_files;
in >> num_files;
for (unsigned i = 0; i < num_files; ++i) {
std::string file;
in >> file;
files.push_back(file);
}
// read mystery filenames
std::vector<std::string>::iterator it;
for (it = files.begin(); it != files.end(); ++it) {
std::ifstream sig(it->c_str());
// sig is your signature file. Read it here
}

#ptic12
your answer helped a lot, i managed to edit/manipulate it to get what i needed out of it.
i created a class for signatures to make it a bit more simple.
this code is written rather simply, and its longer than it needs to be, but it works, later in the project i plan on 'slimming down' a little bit
there are a few things missing from this of course, but it would be a long post if i included them
vector<Signature> MakeSignatures(string DataFile)
{
string SigFile="", MystFile="";
int NumSig=0, NumMystery=0;
ifstream infile(DataFile);// opens data.txt
infile >> NumSig;
vector<Signature> SigStorage;//creates a vector in which to store signature objects
for(int i=0; i <NumSig; i++)
{
infile >> SigFile;
Signature Sig(SigFile);
SigStorage.push_back(SigFile);
}
infile >> NumMystery;
for(int i=0; i < NumMystery; i++)
{
infile >> MystFile;
//not quite done here yet
//large part of project will be called here
}
return SigStorage;
}
and the constructor in the Signature class's .cpp
Signature::Signature(string SigFile)
{
ifstream in(SigFile);
while(!in.eof())
{
getline(in, AuthName); //gets author name
in >> AverageWord; //get next 5 floats
in >> TypeToken;
in >> HapaxLego;
in >> AverageNumber;
in >> SentenceCom;
}
}
hopefully this will help anyone who needs the same sort of help i did.
(didn't really help that the data.txt included a misspelled path, took a while to figure that one out)

Related

How to read text from file itno standard string cpp

I am trying to read about 2 lines from a file of text into a std::string in c plus plus. I have looked through several answers and found none that work on my device. Can anyone tell me what I am doing wrong? The method is currently returning a null string, and doesn't correctly open the file or read it at all.
std::string readFile(std::string filename) {
std::ifstream infile;
infile.open(filename);
std::string output;
if (infile.is_open()) {
while(infile.good()) {
infile >> output;
}
}
infile.close();
return output;
}
Not sure what file you are trying to open but that's a completely separate problem. The code you've written will open a file if you give it a path to a file that it can open. Check your current working directory and confirm the path is correct.
Even after you solve that problem, you're going to have more problems though.
I expect that you are confused because you are repeatedly overwriting output with this line:
infile >> output;
perhaps you meant to declare output as a std::stringstream
And for me it doesn't return an empty string, it returns the last word of the file. I guess it depends what's in your file.

Function not Reading ifstream file

I'm working on code for one of my programming classes and my professor won't allow any of the code to be changed besides that within each function (function arguments and the main function are not allowed to be changed). The issue comes with one of the functions making use of ifstream&.
The issue arises in this specific function, which is supposed to take in the all of the data from the input file (in this case programmers.txt), but the program doesn't read the data from the file at all.
int readProgrammers(ifstream& inputFile, Programmer programmers[], int maxProgrammers )
{
inputFile.open("programmers.txt", std::ios_base::in);
for (int i = 0; i < maxProgrammers; i++)
{
inputFile >> programmers[i].programmer_id;
inputFile >> programmers[i].name;
inputFile >> programmers[i].lines;
}
return 0;
}
I've messed around with .ignore() as well as quadruple checking whether or not I got the name of the file wrong (which I didn't). I also tried going without using .open inside of the function to see if that was messing around with this, but I ended up with the same exact result. I'm honestly not sure as to what the issue is since I rarely use ifstream& in functions as it usually turns out extremely buggy.
For a little more info so as to help, this is the data within the file that's being read.
1 Alvin 300
2 Brenda 350
3 Chris 250
4 Dana 500
5 Eli 450
6 Faye 320
7 Glen 670
8 Hannah 230
9 Ian 420
10 Jade 380
I'm supposed to try and store this information into an array Programmer structs. What I'm doing wrong that's causing the file not to be read?
Edit:
I got rid of the .open within the function and checked with getLine and cout to see if the file is being read, and it is by getLine, so I'm not sure why the data isn't being stored/read by this code:
for (int i = 0; i < maxProgrammers; i++)
{
inputFile >> programmers[i].programmer_id;
inputFile >> programmers[i].name;
inputFile >> programmers[i].lines;
}
Don't call open() on a std::ifstream that is passed in to the function. It should be the caller's responsibility to make sure the stream is open before calling the function. Just read from whatever open stream is given to you.
I suggest you use std::getline() to read the input stream a line at a time, using a std::istringstream to read individual values from each line.
Try this:
int readProgrammers(ifstream& inputFile, Programmer programmers[], int maxProgrammers)
{
int count = 0;
for (int i = 0; i < maxProgrammers; i++)
{
string line;
if (!getline(inputFile, line)) break;
istringstream iss(line);
iss >> programmers[i].programmer_id;
iss >> programmers[i].name;
iss >> programmers[i].lines;
++count;
}
return count;
}
ifstream inputFile("programmers.txt");
Programmer programmers[10];
readProgrammers(inputFile, programmers, 10);

For loops and inputing data?

trying to figure out how to make a little inventory program and I can't for the life figure out why it isn't working.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct record
{
int item_id;
string item_type;
int item_price;
int num_stock;
string item_title;
string item_author;
int year_published;
};
void read_all_records(record records[]);
const int max_array = 100;
int main()
{
record records[max_array];
read_all_records(records);
cout << records[2].item_author;
return 0;
}
void read_all_records(record records[])
{
ifstream invfile;
invfile.open("inventory.dat");
int slot = 0;
for (int count = 0; count<max_array; count++);
{
invfile >> records[slot].item_id >> records[slot].item_type >> records[slot].item_price >> records[slot].num_stock >> records[slot].item_title >> records[slot].item_author >> records[slot].year_published;
slot++;
}
invfile.close();
}
I'm testing it by having it print the second item from records author. When I run it, it doesn't show the authors name at all. The .dat file is located in just about every folder where the project is (I forgot which folder it needs to be in) so it's there.
The issue isn't that the file isn't working. It's the array not printing off anything.
my inv file is basically:
123456
book
69.99
16
title
etc
etc
and repeats for different books/cds etc all on one line, all without spaces. Should just next in.
You should check to see that the file is open.
invfile.open("inventory.dat");
if (!invfile.is_open())
throw std::runtime_error("couldn't open inventory file");
You should check to seen that your file reads are working and breaks when you hit the end of file.
invfile >> records[slot].item_id >> records[slot].item_type ...
if (invfile.bad())
throw std::runtime_error("file handling didn't work");
if (invfile.eof())
break;
You probably want to read each record at time, as it isn't clear from this code how the C++ streams are supposed to differentiate between each field.
Usually you'd expect to use std::getline, split the fields on however you delimit them, and then use something like boost::lexical_cast to do the type parsing.
If I were doing this, I think I'd structure it quite a bit differently.
First, I'd overload operator>> for a record:
std::istream &operator>>(std::istream &is, record &r) {
// code about like you had in `read_all_records` to read a single `record`
// but be sure to return the `stream` when you're done reading from it.
}
Then I'd use an std::vector<record> instead of an array -- it's much less prone to errors.
To read the data, I'd use std::istream_iterators, probably supplying them to the constructor for the vector<record>:
std::ifstream invfile("inventory.dat");
std::vector<record> records((std::istream_iterator<record>(invfile)),
std::istream_iterator<record>());
In between those (i.e., after creating the file, but before the vector) is where you'd insert your error handling, roughly on the order of what #Tom Kerr recommended -- checks for is_open(), bad(), eof(), etc., to figure out what (if anything) is going wrong in attempting to open the file.
Add a little check:
if (!invfile.is_open()) {
cout<<"file open failed";
exit(1);
}
So that way, you don't need to copy your input file everywhere like you do now ;-)
You are reading in a specific order, so your input file should have the same order and required number of inputs.
You are printing 3rd element of the struct records. So you should have at least 3 records. I don't see anything wrong with your code. It would a lot easier if you can post your sample input file.

What's the correct way to read a text file in C++?

I need to make a program in C++ that must read and write text files line by line with an specific format, but the problem is that in my PC I work in Windows, and in College they have Linux and I am having problems because of line endings are different in these OS.
I am new to C++ and don't know could I make my program able read the files no matter if they were written in Linux or Windows. Can anybody give me some hints? thanks!
The input is like this:
James White 34 45.5 10 black
Miguel Chavez 29 48.7 9 red
David McGuire 31 45.8 10 blue
Each line being a record of a struct of 6 variables.
Using the std::getline overload without the last (i.e. delimiter) parameter should take care of the end-of-line conversions automatically:
std::ifstream in("TheFile.txt");
std::string line;
while (std::getline(in, line)) {
// Do something with 'line'.
}
Here's a simple way to strip string of an extra "\r":
std::ifstream in("TheFile.txt");
std::string line;
std::getline(input, line));
if (line[line.size() - 1] == '\r')
line.resize(line.size() - 1);
If you can already read the files, just check for all of the newline characters like "\n" and "\r". I'm pretty sure that linux uses "\r\n" as the newline character.
You can read this page: http://en.wikipedia.org/wiki/Newline
and here is a list of all the ascii codes including the newline characters:
http://www.asciitable.com/
Edit: Linux uses "\n", Windows uses "\r\n", Mac uses "\r". Thanks to Seth Carnegie
Since the result will be CR LF, I would add something like the following to consume the extras if they exist. So once your have read you record call this before trying to read the next.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
If you know the number of values you are going to read for each record you could simply use the ">>" method. For example:
fstream f("input.txt" std::ios::in);
string tempStr;
double tempVal;
for (number of records) {
// read the first name
f >> tempStr;
// read the last name
f >> tempStr;
// read the number
f >> tempVal;
// and so on.
}
Shouldn't that suffice ?
Hi I will give you the answer in stages. Please go trough in order to understand the code.
Stage 1: Design our program:
Our program based on the requirements should...:
...include a definition of a data type that would hold the data. i.e. our
structure of 6 variables.
...provide user interaction i.e. the user should be able to
provide the program, the file name and its location.
...be able to
open the chosen file.
...be able to read the file data and
write/save them into our structure.
...be able to close the file
after the data is read.
...be able to print out of the saved data.
Usually you should split your code into functions representing the above.
Stage 2: Create an array of the chosen structure to hold the data
...
#define MAX 10
...
strPersonData sTextData[MAX];
...
Stage 3: Enable user to give in both the file location and its name:
.......
string sFileName;
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
.....
->Note 1 for stage 3. The accepted format provided then by the user should be:
c:\\SomeFolder\\someTextFile.txt
We use two \ backslashes instead of one \, because we wish it to be treated as literal backslash.
->Note 2 for stage 3. We use ifstream i.e. input file stream because we want to read data from file. This
is expecting the file name as c-type string instead of a c++ string. For this reason we use:
..sFileName.c_str()..
Stage 4: Read all data of the chosen file:
...
while (!inFile.eof()) { //we loop while there is still data in the file to read
...
}
...
So finally the code is as follows:
#include <iostream>
#include <fstream>
#include <cstring>
#define MAX 10
using namespace std;
int main()
{
string sFileName;
struct strPersonData {
char c1stName[25];
char c2ndName[30];
int iAge;
double dSomeData1; //i had no idea what the next 2 numbers represent in your code :D
int iSomeDate2;
char cColor[20]; //i dont remember the lenghts of the different colors.. :D
};
strPersonData sTextData[MAX];
cout << "Enter a file name: ";
getline(cin,sFileName);
ifstream inFile(sFileName.c_str(),ios::in);
int i=0;
while (!inFile.eof()) { //loop while there is still data in the file
inFile >>sTextData[i].c1stName>>sTextData[i].c2ndName>>sTextData[i].iAge
>>sTextData[i].dSomeData1>>sTextData[i].iSomeDate2>>sTextData[i].cColor;
++i;
}
inFile.close();
cout << "Reading the file finished. See it yourself: \n"<< endl;
for (int j=0;j<i;j++) {
cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
<<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
<<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;
}
return 0;
}
I am going to give you some exercises now :D :D
1) In the last loop:
for (int j=0;j<i;j++) {
cout<<sTextData[j].c1stName<<"\t"<<sTextData[j].c2ndName
<<"\t"<<sTextData[j].iAge<<"\t"<<sTextData[j].dSomeData1
<<"\t"<<sTextData[j].iSomeDate2<<"\t"<<sTextData[j].cColor<<endl;}
Why do I use variable i instead of lets say MAX???
2) Could u change the program based on stage 1 on sth like:
int main(){
function1()
function2()
...
functionX()
...return 0;
}
I hope i helped...

Using multiple instances of getline in C++

I've been working on a class assignment for C++ and we're required to acquire input from a text file and assign those values to an array....one is a string, the second an int, and the third a double.
We've only been introduced to arrays and I don't know anything yet about pointers or linked lists, or any of the higher end stuff, so I feel like I'm somewhat limited in my options. I've worked all day trying to figure out a way to acquire input from the text file and assign it to the appropriate array. I've tried to use getline to read the input file and set a delimiter to separate each piece of data but I get an error when I try to use it more than once. From what I've read, this has to do with how I'm overloading the function but I'm at a loss at resolving it. Every explanation I've read about it goes beyond my current level of familiarity. Right now, I'm focused on this fragment of code:
for (int i = 0; i < EMP_NUM; i++) // Get input from text file for names.
getline(inFile, nameAr[i], '*');
for (int i = 0; i < EMP_NUM; i++) // Input for hours.
getline(inFile, hoursAr[i], '*');
for (int i=0; i < EMP_NUM; i++) // Input for hourly rate.
getline(inFile, hrateAr[i], '*');
I'm trying to use getline three times and write the data to three separate arrays, then make a series of calculations with them later and output them to another text file. The first instance of getline doesn't produce any compiler errors but the latter two do. I'm not quite sure of another solution to get the data into my arrays, so I'm at a loss. Any help would be great!
If I understand correctly you merely have three values in a file: a string, an int and a double. I assume they are delimited by whitespace.
If that is so then you don't need std::getline(). Rather, use the extraction operator:
std::ifstream file("input.txt");
std::string s;
if( ! (file >> s) ) { // a single word extracted from the file
// failure
}
int n;
// ...
1) Instead of three different iteration, use only one
2) Pass string object in getline instead of pointers
string buf;
for (int i = 0; i < EMP_NUM; i++) // Get input from text file for names.
{
getline(inFile, buf, '*');
nameAr[i] = buf;
getline(inFile, buf, '*'); //assuming delimiter is again *
hoursAr[i] = atoi(buf.c_str() ); //C way to doing it...however in c++ u have to use stringstreams....
getline(inFile, buf);
hrateAr[i] = atof(buf.c_str() );;
}
What do the compiler errors say? Are you sure that the error is caused by getline? Maybe it's not because the getline calls but because of multiple declarations of i.