Getting input from a file in C++ - c++

I am currently developing an application, which gets the input from a text file and proceeds accordingly. The concept is the input file will have details in this fomat
A AND B
B OR C
Each and every line will be seperated by a blank space and the input must be taken from the text file and processed by logic. I use a TCPP compiler and i am facing problems reading the input. Please help me with the issue...

Reading input a line at a time is normally done with std::getline, something like this:
std::string line;
std::ifstream infile("filename");
while (std::getline(line, infile))
// show what we read
std::cout << line << "\n";
If you're having trouble with things like this, you might consider looking for a (better) book on C++ than whatever you're now (hopefully) using.

Following can be used straightaway:
BOOL ReadFile(CString filename)
{
BOOL bRead = TRUE;
std::ifstream m_strmFile;
m_strmFile.open(filename, std::ios::in);
char pszLine[256];
memset(pszLine, 256, 0);
if (m_strmFile)
{
// Read whatever number of lines in your file
for (unsigned int i = 0; i < 5/*number of lines*/; i++)
m_strmFile.getline(pszLine, 256);
// Do whatever you want to do with your read lines here...
}
else bRead = FALSE;
return bRead;
}

are you using headr files like:
include
or #include and you can make use of the fileobject.getline(), (do check its proper syntax.) function in C++ or for char by char use fileobject.get(ch) kind of function

Related

Picking a random line from a text file

I need to write an 8 ball code that has eleven options to display and it needs to pull from a text file. I have it taking lines from the text file but sometimes it takes an empty line with no writing. And I need it to only take a line that has writing.
Here are that options it needs to draw from:
Yes, of course!
Without a doubt, yes.
You can count on it.
For sure!Ask me later.
I'm not sure.
I can't tell you right now.
I'll tell you after my nap.
No way!I don't think so.
Without a doubt, no.
The answer is clearly NO.
string line;
int random = 0;
int numOfLines = 0;
ifstream File("file.txt");
srand(time(0));
random = rand() % 50;
while (getline(File, line))
{
++numOfLines;
if (numOfLines == random)
{
cout << line;
}
}
}
IMHO, you need to either make the text lines all the same length, or use a database (table) of file positions.
Using File Positions
Minimally, create a std::vector<pos_type>.
Next read the lines from the file, recording the file position of the beginning of the string:
std::vector<std::pos_type> text_line_positions;
std::string text;
std::pos_type file_position = 0;
while (std::getline(text_file, text)
{
text_line_positions.push_back(file_position);
// Read the start position of the next line.
file_position = text_file.tellg();
}
To read a line from a file, get the file position from the database, then seek to it.
std::string text_line;
std::pos_type file_position = text_line_positions[5];
text_file.seekg(file_position);
std::getline(text_file, text_line);
The expression, text_line_positions.size() will return the number of text lines in the file.
If File Fits In Memory
If the file fits in memory, you could use std::vector<string>:
std::string text_line;
std::vector<string> database;
while (getline(text_file, text_line))
{
database.push_back(text_line);
}
To print the 10 line from the file:
std::cout << "Line 10 from file: " << database[9] << std::endl;
The above techniques minimize the amount of reading from the file.

C++ remove empty lines from cin and save to same file

A part of my assignment is to make a program that reads a file that is passed from command line like this: inputfile.cpp | ./pg_rmv_empty_lines.
This (I guess) is for that reason that later on I can pipe(?) the same file to multiple programs.
I know I can read lines in that file with:
int main()
{
string line;
while(getline(cin, line))
{
cout << line << endl;
}
return 0;
}
What I need to do, is to remove all empty lines in the file that the program receives, remove those lines and then save the modified file.
I don't know the name of the file that needs modification, it's passed from the command line by "client"
Filename should stay the same after the modifications.
This is confusing me because every example I find, people suggests something that includes hardcoding filename into the source code like outfile.open("movieList.txt",ios_base::app);. In my case I don't know the name of the input file.
Bear in mind that I'm using C++ first time and it's already making me lose my faith in humanity.
To get the filename you need to parse command line arguments. Once you've done that, examples you referred to will work to read the lines from the file. Assuming file isn't big, you can read it into the memory, skipping the empty lines using if statement.
Once you've read the file into memory, you should either close it and re-open for writing or reset to the beginning and write the buffer out.
If the file is large and couldn't be read into the memory buffer, you only can pull this out by doing one line (or limited number of lines) at a time and save the results into a temporary file with a different name. After that you'd have to delete the old file and rename the new file. Of course, the other way (first rename original file and then save new one with the old name) works as well.
Getting the filename from the command line is easy.
#include <iostream>
#include <fstream>
#include <string> // Because why not.
int main(int argc, char** argv) {
if (argc != 2) {
return -1; // Indicates error
}
std::string filename = argv[1];
std::ifstream input(filename);
// Do your stuff...
return 0;
}
No more hints :-)
Are you sure that the requirement is to use the pipe command? I think what you want is to use command line arguments. Maybe this article here helps:
http://www.cplusplus.com/articles/DEN36Up4/
You can define your main function as:
int main(int argc, char* argv[])
{
...
}
and then argc is the amount of commandline arguments were given and argv is the arguments. The first argument is always the name of your program. So if you execute myprogram.exe ./pg_rmv_empty_lines, argv[0] would be myprogram.exe and argv[1] would be ./pg_rmv_empty_lines
You can then use this to dynamically read from that file in your code but you first need to open the file. For example something along the lines of:
std::ifstream myFile;
std::string lineAsString;
myFile.open(argv[1]);
std::getline(myFile, lineAsString);
... do things with the line
myFile.close();

Decoding / Encloding Text File using Stack Library - Can't Encode Large Files C++

I am working on a program that can encode and then decode text in C++. I am using the stack library. The way the program works is that it first asks you for a cypher key, which you put in manually. It then asks for the file name, which is a text file. If it is a normal txt file, it encodes the message to a new file and adds a .iia files extension. If the text file already has a .iia file extension, then it decodes the message, as long as the cypher key is the same as the one used to encode it.
My program does encode and decode, but how many characters it decodes is determined by temp.size() % cypher.length() that is in the while loop in the readFileEncode() function. I think this is what is keeping the entire file from being encoded and then decoded correctly. Another words, the ending file after it has been decoded from say "example.txt.iia" back to "example.txt" is missing a large portion of the text from the original "example.txt" file. I tried just cypher.length() but of course that does not encode or decode anything then. The entire process is determined by that argument for the decoding and encoding.
I cannot seem to find out the exact logic for this to encode and decode all the characters in any size file. Here is the following code for the function that does the decoding and encoding:
EDIT: Using WhozCraig's code that he edited for me:
void readFileEncode(string fileName, stack<char> &text, string cypher)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
stack<char> temp;
char ch;
while (file.get(ch))
temp.push(ch ^ cypher[temp.size() % cypher.length()]);
while (!temp.empty())
{
text.push(temp.top());
temp.pop();
}
}
EDIT: A stack is required. I am going to implement my own stack class, but I am trying to get this to work first with the stack library. Also, if there is a better way of implementing this, please let me know. Otherwise, I believe that there is not much wrong with this except to get it to go through the loop to encode and decode the entire file. I am just unsure as to why it stops at, say 20 characters sometimes, or ten characters. I know it has to do with how long the cypher is too, so I believe it is in the % (mod). Just not sure how to rewrite.
EDIT: Ok, tried WhozCraig's solution and I don't get the desired output, so the error now must be in my main. Here is my code for the main:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cctype>
#include <stack>
using namespace std;
void readFileEncode(string fileName, stack<char> &text, string cypher);
int main()
{
stack<char> text; // allows me to use stack from standard library
string cypher;
string inputFileName;
string outputFileName;
int position;
cout << "Enter a cypher code" << endl;
cin >> cypher;
cout << "Enter the name of the input file" << endl;
cin >> inputFileName;
position = inputFileName.find(".iia");//checks to see if the input file has the iia extension
if (position > 1){
outputFileName = inputFileName;
outputFileName.erase(position, position + 3);// if input file has the .iia extension it is erased
}
else
//outputFileName.erase(position, position + 3);// remove the .txt extension and
outputFileName = inputFileName + ".iia";// add the .iia extension to file if it does not have it
cout << "Here is the new name of the inputfile " << outputFileName << endl; // shows you that it did actually put the .iia on or erase it depending on the situation
system("pause");
readFileEncode(inputFileName, text, cypher); //calls function
std::ofstream file(outputFileName); // calling function
while (text.size()){// goes through text file
file << text.top();
text.pop(); //clears pop
}
system("pause");
}
Basically, I am reading .txt file to encrypt and then put a .iia file extension on the filename. Then I go back through, enter the file back with the .iia extension to decode it back. When I decode it back it is gibberish after about the first ten words.
#WhozCraig Does it matter what white space, newlines, or punctuation is in the file? Maybe with the full solution here you can direct me at what is wrong.
just for information: never read file char by char it will take you hours to finish 100Mb.
read at least 512 byte(in my case i read directly 1 or 2Mb ==> store in char * and then process).
If I understand what you're trying to do correctly, you want the entire file rotationally XOR'd with the chars in the cipher key. If that is the case, you can probably address your immediate error by simply doing this:
void readFileEncode(string fileName, stack<char> &text, string cypher)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
stack<char> temp;
char ch;
while (file.get(ch))
temp.push(ch ^ cypher[temp.size() % cypher.length()]);
while (!temp.empty())
{
text.push(temp.top());
temp.pop();
}
}
The most notable changes are
Opening the file in binary-mode using std::ios::in|std::ios::binary for the open-mode. this will eliminate the need to invoke the noskipws manipulator (which is usually a function call) for every character extracted.
Using file.get(ch) to extract the next character. The member will pull the next char form the file buffer directly if one is available, otherwise load the next buffer and try again.
Alternative
A character by character approach is going to be expensive any way you slice it. That this is going through a stack<>, which will be backed by a vector or deque isn't going to do you any favors. That it is going through two of them just compounds the agony. You may as well load the whole file in one shot, compute all the XOR's directly, then push them on to you stack via a reverse iterator:
void readFileEncode
(
const std::string& fileName,
std::stack<char> &text,
const std::string& cypher
)
{
std::ifstream file(fileName, std::ios::in|std::ios::binary);
// retrieve file size
file.seekg(0, std::ios::end);
std::istream::pos_type pos = file.tellg();
file.seekg(0, std::ios::beg);
// early exit on zero-length file.
if (pos == 0)
return;
// make space for a full read
std::vector<char> temp;
temp.resize(static_cast<size_t>(pos));
file.read(temp.data(), pos);
size_t c_len = cypher.length();
for (size_t i=0; i<pos; ++i)
temp[i] ^= cypher[i % c_len];
for (auto it=temp.rbegin(); it!=temp.rend(); ++it)
text.push(*it);
}
You still get your stack on the caller-side, but I think you'll be considerably happier with the performance.

Reading and writing to files isn't working in C++

I am basically trying to reverse the contents of a text file. When I run this code, nothing happens. Code:
getArguments();
stringstream ss;
ss << argument;
string fileName;
ss >> fileName;
fstream fileToReverse(fileName);
if (fileToReverse.is_open()) {
send(sock, "[*] Contents is being written to string ... ", strlen("\n[*] Contents is being written to string ... "), 0);
string line;
string contentsOfFile;
while (getline(fileToReverse, line)) {
contentsOfFile.append(line);
line = "\0";
}
send(sock, "done\n[*] File is being reversed ... ", strlen("done\n[*] File is being reversed ... "), 0);
string reversedText(contentsOfFile.length(), ' ');
int i;
int j;
for(i=0,j=contentsOfFile.length()-1;i<contentsOfFile.length();i++,j--) {
reversedText[i] = contentsOfFile[j];
}
contentsOfFile = "\0";
fileToReverse << reversedText;
fileToReverse.close();
send(sock, "done\n", strlen("done\n"), 0);
}
fileName is created from user input, and I know that the file exists. It just doesn't do anything to the file. If anyone has any ideas that they would like to share that would be great.
UPDATE:
I now can write reversedText to the file but how can I delete all of the files contents?
In this particular case, when you have read all the input content, your file is in an "error state" (eof and fail bits set in the status).
You need to clear that with fileToReverse.clear();. Your file position will also be at the end of the file, so you need to use fileToReverse.seekp(0, ios_base::beg) to set the position to the beginning.
But I, just as g-makulik, prefer to have two files, one for input and one for output. Saves a large amount of messing about.
When you need to debug something like this - saying "all the functions are being run and all the variables are being created, and it compiled without any warnings" isn't really debugging.
Debugging - this doesn't work. Remove bits until you find what doesn't work. Like you said - all variables are what you expect them. So... try and see if, for example, the way you read and write from a file works. Just write a small program that opens a file like you open it, reads from it like you do and then writes... whatever back into it in the same way you do. See if that works.
In other words, try and find the smallest program that reproduces what you see.

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...