C++ file reading - c++

I have a file that has a number in which is the number of names that follow. For example:
4
bob
jim
bar
ted
im trying to write a program to read these names.
void process_file(ifstream& in, ofstream& out)
{
string i,o;
int tmp1,sp;
char tmp2;
prompt_user(i,o);
in.open (i.c_str());
if (in.fail())
{
cout << "Error opening " << i << endl;
exit(1);
}
out.open(o.c_str());
in >> tmp1;
sp=tmp1;
do
{
in.get(tmp2);
} while (tmp2 != '\n');
in.close();
out.close();
cout<< sp;
}
So far I am able to read the first line and assign int to sp
I need sp to be a counter for how many names. How do I get this to read the names.
The only problem I have left is how to get the names while ignoring the first number.
Until then i cannot implement my loop.

while (in >> tmp1)
sp=tmp1;
This successfuly reads the first int from the and then tries to continue. Since the second line is not an int, extraction fails, so it stops looping. So far so good.
However, the stream is now in fail state, and all subsequent extractions will fail unless you clear the error flags.
Say in.clear() right after the first while loop.
I don't really see why you wrote a loop to extract a single integer, though. You could just write
if (!(in >> sp)) { /* error, no int */ }
To read the names, read in strings. A loop is fine this time:
std::vector<std::string> names;
std::string temp;
while (in >> temp) names.push_back(temp);
You'd might want to add a counter somewhere to make sure that the number of names matches the number you've read from the file.

int lines;
string line;
inputfile.open("names.txt");
lines << inputfile;
for(i=0; i< lines; ++i){
if (std::getline(inputfile, line) != 0){
cout << line << std::endl;
}
}

First of all, assuming that the first loop:
while (in >> tmp1)
sp=tmp1;
Is meant to read the number in the beginning, this code should do:
in >> tmp1;
According to manual operator>>:
The istream object (*this).
The extracted value or sequence is not returned, but directly stored
in the variable passed as argument.
So don't use it in condition, rather use:
in >> tmp1;
if( tmp1 < 1){
exit(5);
}
Second, NEVER rely on assumption that the file is correctly formatted:
do {
in.get(tmp2);
cout << tmp2 << endl;
} while ( (tmp2 != '\n') && !in.eof());
Although whole algorithm seems a bit clumsy to me, this should prevent infinite loop.

Here's a simple example of how to read a specified number of words from a text file in the way you want.
#include <string>
#include <iostream>
#include <fstream>
void process_file() {
// Get file name.
std::string fileName;
std::cin >> fileName;
// Open file for read access.
std::ifstream input(fileName);
// Check if file exists.
if (!input) {
return EXIT_FAILURE;
}
// Get number of names.
int count = 0;
input >> count;
// Get names and print to cout.
std::string token;
for (int i = 0; i < count; ++i) {
input >> token;
std::cout << token;
}
}

Related

Sorting function with output to a separate file

I need to sort the input text document and write it into another test document. so that lines with an even number of words delete every second word, and lines with an odd number of words remain unchanged. The sorting should be performed as a function, the first pointer to the input of the string and the second pointer to the output.
I did the input and output, tried to do a sorting to begin with without a function, but nothing worked. can you tell me what I did not do the rule?
Example:
Input.txt
I do not like to go to school or study
I like to play games
Output.txt
I not to to or
I like to play games
string in, out;
cin >> in;
cin >> out;
ifstream input(in);
string str;
ofstream output(out);
string st;
while (getline(input, str))
{
do
{
int i = count(str.cbegin(), str.cend(), ' ');
if (i % 2 == 0)
st.append(str);
else
st.append(" ");
i++;
}
while (input);
output << st << endl;
}
The std::stringstream will be your friend.
Read about it here and especially for the useful std::istringstream here.
What can we do with this thing? We can put a string into it and then use the extraction operator >> like with any other stream.
So, counting words will become very simple. We read a line from the file as a std::string and then put it into a std::istringstream, Then we extract dummy words and increase a counter until the reading fails. Then we have the number of words.
Example:
// We read one line. Count the number of words
// Put the string in a stringstream to easily extract words
std::istringstream iss(line);
// Counter for words
unsigned int wordCount{};
// Dummy word
std::string tempWord{};
// Do the counting
while (iss >> tempWord) ++wordCount;
The stream tries too read until it cannot read any more (the stream is empty) and then sets a failbit. The failure of any stream can be checked with its bool operator or the !-operator. The while loop expects a boolean. And the extraction operation iss >> tempWord will return a reference to the stream and then its bool operator will be called and used as condition.
OK, understood, we can now count words. Next step is to skip words.
This is similar simple. In case of even number of words in a string, we will read always 2 words in a loop and simply throw the second one away.
Like this
std::string usedWord{};
// Read 2 words, ignore the second
while (iss >> usedWord >> tempWord)
result += (usedWord + ' ');
There are of course many other possible ways to solve that, but maybe the below solution can give you an idea.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main() {
// First read the input filename
std::cout << "\nPlease enter the path for the input file:\n";
std::string inputFileName{};
std::getline(std::cin, inputFileName);
// next read the output filename
std::cout << "\nPlease enter the path for the output file:\n";
std::string outputFileName{};
std::getline(std::cin, outputFileName);
// Open now both files. If one file cannot be opened, then no need tocontinue
// Open input file and check, if it could be opened
std::ifstream inputFileStream(inputFileName);
if (inputFileStream) {
// Input file could be opened without error.
// Now open output file and check, if it could be opened
std::ofstream outputFileStream(outputFileName);
if (outputFileStream) {
// Now, both input and output file streams are open
// Read lines
std::string line{};
while (std::getline(inputFileStream, line)) {
// We read one line. Count the number of words
// Put the string in a stringstream to easily extract words
std::istringstream iss(line);
// Counter for words
unsigned int wordCount{};
// Dummy word
std::string tempWord{};
// Do the counting
while (iss >> tempWord) ++wordCount;
// if the number of words is even then
if ((wordCount % 2) == 0) {
// Rinitialize stringstream
iss.clear(), iss.str(line);
// Here we store the resulting sentence
std::string result{};
// Now extract the word that we will keep and the other one that we will throw away
std::string usedWord{};
// Read 2 words, ignore the second
while (iss >> usedWord >> tempWord)
result += (usedWord + ' ');
// Write result to output
outputFileStream << result << '\n';
}
else
outputFileStream << line << '\n';
}
}
else std::cerr << "\n*** Error: could not open output file '" << outputFileName << "'\n\n";
}
else std::cerr << "\n*** Error: could not open input file '" << inputFileName << "'\n\n";
}

Stop input loop when input is done | std::cin

I want to write a function that gets a set of integers and saves them to a vector.
To get the integers I'm using a while loop.
Enter the vector elements: 1 2 3 4 5
I want the loop to stop looking for input after the last element is inputted or until a non-numberis inputted, however I'm having trouble with it.
It is an assignment, so it needs to read input from std::cin.
This is my code:
#include <iostream>
#include <vector>
bool NumInVect(int num, std::vector<int> vect)
{
bool numInVect = false;
for (int i = 0; i < vect.size(); i++)
{
if (vect[i] == num)
{
numInVect = true;
}
}
return numInVect;
}
int main() {
std::vector<int> tempVect;
std::vector<int> finalVector;
std::cout << "Enter the vector elements: ";
int currVal;
while (std::cin >> currVal)
{
std::cout << "-\n";
if (!NumInVect(currVal, tempVect))
{
tempVect.push_back(currVal);
}
std::cout << currVal << std::endl;
}
//the code never reaches this loop, since its stuck in the while loop
std::cout << "knak\n";
for (int i = 0; i < tempVect.size(); i++)
{
std::cout << tempVect[i];
}
}
I've tried doing multiple things like using std::cin.eof()/.fail(), std::cin >> currVal in the while loop, a do-while loop, but I can't seem to figure out how to get this to work. Does anyone have any tips on what to look into or how to approach this?
If your intention is to get all the input from a given line, and add individual numbers to the vector, then you want to read a line of input into a string, then use an istringstream to process that line of input.
A simplified example:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main() {
std::vector<int> tempVect;
std::string line;
std::getline( std::cin, line );
std::istringstream iss( line );
int curVal;
while ( iss >> curVal ) {
tempVect.push_back( curVal );
}
}
You should add a condition in your while loop so that it breaks when you want like:
if (temptVect.size() >= 5)
break;
I want the loop to stop looking for input after the last element is inputted or until a non-numberis inputted,
This loop should do exactly that.
while (std::cin >> currVal)
{
std::cout << "-\n";
if (!NumInVect(currVal, tempVect))
{
tempVect.push_back(currVal);
}
std::cout << currVal << std::endl;
}
This test while (std::cin >> currVal) will fail if read does not work and exit the loop. Since currVal is an integer, it will fail as soon as it tries to read something that is not an integer (note space and new lines are completely ignored).
What may be the issue is that std::cin is buffered. You can type a long time before filling up the buffer and causing the operator>> to do anything. To force this operator to read you have to force a flush this is usually done by hitting <enter> on the keyboard.
After the buffer is flushed it will read all the numbers on the input and exit the loop if a read fails. So you need to explicitly type not a number before hitting the <enter>.
eg:
1 2 3 4 5 X<enter>
or:
1<enter>
2<enter>
3<enter>
4<enter>
5<enter>
X<enter>
You need that non number to force the read to fail and the loop to exit.
Alternatively, you could say I want to read all the numbers on one line then exit the loop.
In that case: You should read a line and the processes the line. This is only a slight change from your above code.
std::string line; // Hold a line of text
std::getline(std::cin, line); // Read a line of text.
std::stringstream lineStream(line); // Convert string into stream
while (lineStream >> currValue) // Read each integer from the stream.
{ // Exits when the read fails to read
// a number becuase it is empty.
// The other stuff like before.
}

Encode a string of characters given a custom code table

I want to programmatically convert a string of characters stored in a file to a string of character codes (encode) by following a code table. The string of binary codes should then go to a file, from which I can revert it back to the string of characters later (decode). The codes in the code table were generated using Huffman algorithm and the code table is stored in a file.
For example, by following a code table where characters and its corresponding codes are single spaced like this:
E 110
H 001
L 11
O 111
encoding "HELLO" should output as "0011101111111"
My C++ code cannot seem to complete the encoded string. Here is my code:
int main
{
string English;
ifstream infile("English.txt");
if (!infile.is_open())
{
cout << "Cannot open file.\n";
exit(1);
}
while (!infile.eof())
{
getline (infile,English);
}
infile.close();
cout<<endl;
cout<<"This is the text in the file:"<<endl<<endl;
cout<<English<<endl<<endl;
ofstream codefile("codefile.txt");
ofstream outfile ("compressed.txt");
ifstream codefile_input("codefile.txt");
char ch;
string st;
for (int i=0; i<English.length();)
{
while(!codefile_input.eof())
{
codefile_input >> ch >> st;
if (English[i] == ch)
{
outfile<<st;
cout<<st;
i++;
}
}
}
return 0;
}
For an input string of "The_Quick_brown_fox_jumps_over_the_lazy_dog", the output string is 011100110, but it should be longer than that!
output image
Please help! Is there anything I have missed?
(n.b. my C++ code has no syntax errors)
Let's take a look at the main loop, you are doing your work in:
for (int i=0; i<English.length();)
{
while(!codefile_input.eof())
{
codefile_input >> ch >> st;
if (English[i] == ch)
{
outfile<<st;
cout<<st;
i++;
}
}
}
Your code, will read through the codefile_input once, and then will get stuck in codefile_input.eof () == true condition, and then, for (int i=0; i<English.length();) will become an infinite loop, due to the fact, that there won't be a code path, in which i is increased, and it will never reach the value equal to English.length ().
As a side note, take a read on Why is iostream::eof inside a loop condition considered wrong?.
To avoid the issue, explained above, consider reading the dictionary file, to a data container (e.g. std::map), and then, use that, while iterating through the string, that you want to encode.
For example:
std::ifstream codefile_input("codefile.txt");
char ch;
std::string str;
std::map<char, std::string> codes;
while (codefile_input >> ch >> str)
{
codes[ch] = str;
}
codefile_input.close ();
for (int i=0; i<English.length(); ++i)
{
auto it = codes.find (English[i]);
if (codes.end () != it)
{
outfile << codes->second;
cout << codes->second;
}
}
Note, you will need to #include <map> to use std::map.
In addition to solving the issue, about which, your question, was actually, about, your loop:
while (!infile.eof())
{
getline (infile,English);
}
only reads the last line of the file, while discarding all other lines, that came prior to it. If you want to process all the lines in a file, consider changing that loop to:
while (std::getline (infile, English))
{
/* Line processing goes here */
}
And, since, your dictionary is unlikely to be different for different lines, you can move that logic, to the front of this loop:
std::ifstream codefile_input("codefile.txt");
char ch;
std::string str;
std::map<char, std::string> codes;
while (codefile_input >> ch >> str)
{
codes[ch] = str;
}
codefile_input.close ();
ifstream infile("English.txt");
if (!infile.is_open())
{
cout << "Cannot open file.\n";
exit(1);
}
ofstream outfile ("compressed.txt");
string English;
while (std::getline (infile, English))
{
for (int i=0; i<English.length(); ++i)
{
auto it = codes.find (English[i]);
if (codes.end () != it)
{
outfile << codes->second;
cout << codes->second;
}
}
}
In addition, consider adding error checking for all of the files that you open. You check if you can open file English.txt, and exit if you can't, but you don't check if you could open any other file.
On unrelated note #2, considering reading Why is “using namespace std” considered bad practice? (that's why you see me using std:: explicitly in the code, that I added).

Reading char from file and writing to another file

I am quite new in c++ and programming so sorry in advance in my question repeats. I have a text file of 3 lines:
7
00000000000000000000000*0000
0 0 0 R 0
What I need to do is read 2nd line and write it into an array as char. But I must not include 3rd line because it will go to a completely different matrix. My code so far :
ifstream input;
input.open("input1.txt");
input >> start;
char a=0;
string line;
while (getline(input, line))
{
a=0;
istringstream iss(line);
int length = line.size();
for (int i=0; i<length; i++)
{
iss >> a;
A[i] = a;
cout << A[i] << " " << i << endl;
}
}
input.close();
However, with this code it always starts new array for 3rd line. What am I doing wrong? What is the easiest way to fix it? Thank you.
-----------------------------Update--------------------------------------
I have modified the code but it still does not work properly. I am getting this kind of result : 5)-└ instead of correct one. My current code:
void Read(int &numLines, int &start, vector<char>&A, char B[][5])
{
ifstream input;
input.open("input.txt");
input >> start;
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
string line;
if(getline(input, line))
{
for(char temp: line)
{
A.push_back(temp);
}
}
input.close();
}
A here is a vector I want to write 2nd line to, char by char
Start is just an integer in which I am storing 1st line (7)
Thank you very much for advices
Mixing >> and std::getline is non-trivial. For example, after input >> start; the end of line marker is left in the stream in case it's still needed. In your case it isn't, and it is picked off by the subsequent call to getline, resulting in a read of an empty line.
This is what's complicating your read of line and forcing the while loop and test for empty lines.
Step through your program with your development environment's debugger and you'll see what I'm talking about. Get used to using the debugger. It's possibly the best programming productivity tool you'll ever encounter.
The easiest way to fix it is to place
input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
after
input >> start;
to eat up the end of the line (and anything else that might be on that line. This needs the addition of #include<limits> to get std::numeric_limits<std::streamsize>::max.
Then you can remove the while loop and replace it with
if (getline(input, line))
No loop, not chance of consuming multiple lines from the file. And the logic for reading and processing the third line can follow.
Side note: instead of that for loop, consider
int i = 0;
while (iss >> a)
{
A[i] = a;
cout << A[i] << " " << i << endl;
i++;
}
This will march through iss until it hits the end of the line. You can also throw iss out entirely and just read the characters directly out of line.
int i = 0;
for(char temp: line)
{
A[i] = temp;
}
And A should probably be a vector if it isn't already to reduce the chances of buffer overruns.
for(char temp: line)
{
A.push_back(temp);
}
I would go with something like this:
std::string start;
std::string Astring;
ifstream input;
input.open("input.txt");
input >> start;
input >> Astring;
// If you really want a char array
char * A = new char[Astring.size()];
for (unsigned int i = 0; i < Astring.size(); i++) {
A[i] = Astring[i];
}
// Don't forget to delete after use
delete[] A;
Moreover, if you just need the char array as an input to something else later, you can call Astring.c_str() instead of that for loop, which returns a C-style char array.

Advance File Pointer to skip over number in a file

I was wondering If I could jump positions in a text file.
Suppose I have this file.
12
8764
2147483648
2
-1
Whenever I try to read the third number it won't read because its larger than the max number for a 32 bit int.So whenever i reach the third number, it keeps reading the second over and over again. How can I jump to the 4th number?
Use std::getline instead of operator>>(std::istream, int)
std::istream infile(stuff);
std::string line;
while(std::getline(infile, line)) {
int result;
result = atoi(line.c_str());
if (result)
std::cout << result;
}
The reason you are experiencing the behavior that you are, is that when the std::istream tries (and fails) to read in an integer, it sets a "badbit" flag which means that something went wrong. As long as that badbit flag remains set, it won't do anything at all. So it's not actually re-reading in that line, it's doing NOTHING, and leaving the value that had been there alone. If you want to keep more in line with what you already had, it's probably like below. The above code is simpler and less error prone though.
std::istream infile(stuff);
int result;
infile >> result; //read first line
while (infile.eof() == false) { //until end of file
if (infile.good()) { //make sure we actually read something
std::cout << result;
} else
infile.clear(); //if not, reset the flag, which should hopefully
// skip the problem. NOTE: if the number is REALLY
// big, you may read in the second half of the
// number as the next line!
infile >> result; //read next line
}
You can first read the line, then convert the line to integer if you can. Here is an example for your file :
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main()
{
std::ifstream in("file");
std::string line;
while (std::getline(in, line)) {
int value;
std::istringstream iss(line);
if (!(iss >> value)) {
std::istringstream iss(line);
unsigned int uvalue;
if (iss >> uvalue)
std::cout << uvalue << std::endl;
else
std::cout << "Unable to get an integer from this" << std::endl;
}
else
std::cout << value << std::endl;
}
}
As an alternative to using std::getline(), you could call std::ios::clear(). Consider this excerpt from your previous question
fin >> InputNum;
You could replace that code with this:
fin >> InputNum;
if(!fin)
fin.clear();