C++ getline pass file or cin - c++

I searched internet and read manuals for hours but I can't figure out this one:
My program gets one optional argument, which is file name. Consider this conditions
std::ifstream file;
if (argc > 1) {
file.open(argv[1]);
}
if (file.is_open()) {
processInput(file);
file.close();
} else {
processInput(std::cin);
}
in function processInput I'm trying to read all lines from input and do something with them like this:
void processInput(std::basic_istream<char> inputStream) {
std::string line;
while (std::getline(inputStream, line)) {
processLine(line);
}
}
but I'm getting an error in basic_istream, so I don't have any clue what type should I pass to this function. I tried only blind shots.

Streams are not copyable. You have to pass the stream by reference:
// v-- here
void processInput(std::basic_istream<char> &inputStream) {
By the way, there's a shorter way to write std::basic_istream<char>, which is
void processInput(std::istream &inputStream) {

Related

fstream reading error (only reading first line)

I want to read a file with std::getline. but reads first line only
string FileReader::readLine() {
string line;
string read;
ifstream ReadFile;
ReadFile.open("input.txt");
if (ReadFile.is_open()) {
getline(ReadFile, line);
//ReadFile.close();
}
return line;
}
this is my method. I call this method several time but always reads first line how can i do to read next lines?
You need to change your program flow.
Don't return a string. Use the line within the loop to do whatever it is you want. Ensuring that you either don't leave the method or return to it.
You can't keep coming back to a function like this, as it will keep reading from the beginning.
void FileReader::readLine() {
string line;
string read;
ifstream ReadFile;
ReadFile.open("input.txt");
if (ReadFile.is_open()) {
while(getline(ReadFile, line))
{
//do what you want with that line, but return program flow here.
}
ReadFile.close();
}
}

Error using getline with ifstream - C++

I need help, I tried googling if I could find a similar problem but the solutions for others didn't work for me.
I'm trying to use getline() to read the file I've opened but it's not accepting the parameters I've given it.
What I'm trying to accomplish at this time (not the entire program) is to open a .csv file and determine how many elements it has inside by using getline() and using the , character as the delimiter. My loop has an index which I could just add 1 to it so that I can get the total number of elements inside the file.
The reason I'm doing this is because I intend to use it for a project at school but so far I've gotten stuck at the getline() error:
no matching function for call to 'std::basic_ifstream::getline(std::string&, int, const char [2])'
My code is here:
void readfile(string a)
{
int i = 0;
ifstream infile;
infile.open(a.c_str());
string temp;
//count how many elements are inside
if(infile.is_open())
{
while(infile.good())
{
infile.getline(temp, 256, ",");
i++;
}
infile.close();
i+=1;
}
else
{
cout<<"Error opening file.";
}
cout<<i;
}
Use the free getline() function:
std::string line;
getline(infile, line);
In addition to the answer by #UlrichEckhardt, I'd handle delimiters like this:
if(infile.is_open())
{
string temp;
// std::getline(std;:istream&, std::string) used below
while(getline(infile, temp)) {
std::stringstream stream(str);
std::string token;
while (std::getline(stream, token, ','))
if (!token.empty()) // it's up to you to decide how to handle empty tokens
i++;
}
}
Note the ','. If it were ".", this would be considered a string by the compiler, which is exactly what you're seeing in the error message: a '\0' is appended automatically, thus producing a char[2].

getline() from a textfile error

For a lab for school I am trying to get lines from a text file and display them.
My start:
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <playlist.h>
using namespace std;
void readLine(vector<string> playlist);
int totalTime();
void displayData();
int main()
{
vector<string> playlist;
readLine(playlist);
totalTime();
displayData();
system("pause");
return 0;
}
void readLine(vector<string> playlist)
{
string currentline;
int i = 0;
while (getline("Playlist.txt", currentline) && !empty(currentline))
{
getline("Playlist.txt", playlist[i]);
i = i + 1;
}
}
int totalTime()
{
}
void displayData()
{
}
It seems that I am misusing the getline? The two "getline"s have error underlines saying:
getline
Error: no instance of overloaded function "getline" matches the
argument list argument types are: (const char [13], std::string)
I don't know the cause of the error.
You aren't missing the getline function, you're using it wrong.
getline expects an std::istream& and a std::string&. You need to open a std::ifstream to the file and pass this stream as the first parameter.
See here:
http://www.cplusplus.com/reference/string/string/getline/
Modify the readLine() function like so, either pass in the playlist as a reference or return the playlist vector and move it into another vector, because unless you are doing something you excluded from your code the playlist vector would be lost
vector<string> readLine(vector<string> playlist)
{
ifstream fin;
fin.open("Playlist.txt");
if (!fin) {
cerr << "Could not open file Playlist.txt" << endl;
exit(1);
}
string currentline;
int i = 0;
while (getline(fin, currentline) && !empty(currentline))
{
getline(fin, playlist[i]);
i = i + 1;
}
return playlist;
}
This is because the declaration of version of getline you are trying to look looks like so
istream& getline (istream& is, string& str);
This expects a reference to an istream object as the first type and if you see the inheritance hierarchy here http://www.cplusplus.com/reference/fstream/ifstream/?kw=ifstream you will see that an object of type ifstream inherits from istream
NOTE : As pointed out in the comments below what you are doing does not seem to be right. I do not know how I missed this. But what you are doing seems to be wrong. If your intention is to make the playlist vector store all non empty lines in the text file you should have a loop like so
string temp;
while (getline(fin, temp)) {
if (!temp.empty()) {
lines.push_back(temp);
}
}
Additionally want to check for spaces you would need to program that logic in as well

Is there an elegant way to determine if an ifstream is attached to stdin?

My program is a common shell that I am trying to write in C++. In addition to taking commands from the command line it has to be able to read commands in a file - the file name being passed as an optional arg, not by redirection.
If the arg is present I open the passed filename otherwise I open "/dev/stdin". I'm not thrilled about opening the dev file and it isn't my main question but if someone has a better method I would love to hear it.
Eventually I have to read commands given to the shell but first I must present the prompt if it I am reading from stdin or skip the prompt if the input is coming from a file. My question is: is there a better way to determine in getCommand if the input stream is stdin than declaring a global or passing a bool or similar hacks?
It occurs to me that if I can somehow use std::cin rather than opening the /dev file I can pass the stream as an istream. Would that make it easier to distinguish between the two? E.G. if (source == cin) ?
Thanks for any and all suggestions.
bool getCommand(ifstream source, std::string command)
{
if (source == stdin)
//print prompt to stdout
// do the rest of stuff
return true;
}
int main(int argc, char *argv[])
{
std::ifstream input;
std::string command;
if (argc == 2)
{
input.open(argv[1], std::ifstream::in);
if (! input)
{
perror("input command file stream open");
exit(EXIT_FAILURE);
}
}
else
{
input.open("/dev/stdin", std::ifstream::in);
if (! input)
{
perror("input stdin stream open");
exit(EXIT_FAILURE);
}
}
//.......
if (getCommand(input, command))
//.......
}
If you use std::istream& as the type of your variable then you can use std::cin instead of opening /dev/stdin:
std::ifstream fileinput;
if (argc == 2)
{
fileinput.open(argv[1], std::ifstream::in);
if (! fileinput)
{
perror("input command file stream open");
exit(EXIT_FAILURE);
}
}
std::istream &input = (argc == 2) ? fileinput : std::cin;
The remainder of your question should be about identifying a tty (Detect if stdin is a terminal or pipe?). But failing that, once you've made the above change you could compare with the address of std::cin:
if (&input == &std::cin) {
std::cout << "prompt:";
}
Obviously that won't identify the case where the command line argument is /dev/stdin, so it's a bit of a bodge. But I'd probably argue that's actually an improvement given the funny requirement, because someone can at least write yourprogram /dev/stdin < input.txt, or sort input.txt | yourprogram /dev/stdin in order to work around your restriction and avoid the prompt :-)
First off, if you want to read either from std::cin or from a std::ifstream, I would implement the work in terms of an std::istream and certainly avoid opening /dev/stdin:
std::istream in(std::cin.rdbuf());
std::ifstream fin;
if (argc == 2) {
fin.open(av[1]);
// check that the file is actually open or produce an error
in.rdbuf(fin.rdbuf());
}
else {
// determine if you need to create a prompt
}
if (getCommand(in, command)) {
...
}
Now, to determine if you actually need to write a prompt it isn't sufficient to determine if you are reading from standard input but you also need to determine if the standard input is connected to something with a screen and a keyboard. There is no portable way to do so, however. On UNIXes there are functions like isatty() which can be used to determine if file descriptor 0 is connected to a tty. I would use this information to set up an iword() which can then be used to check if the stream need a prompt:
static int const needs_prompt = std::ios_base::xalloc();
...
in.iword(needs_prompt) = isatty(0);
...
if (in.iword(needs_prompt)) {
std::cout << "pompt>";
}
If you want to get fancy you can create a custom std::streambuf which is hooked up with an std::ostream which is tie()ed to the input stream stream and writes a prompt upon sync(): Every time a read operation on an input stream is done the tie()ed std::ostream is flushed. However, this requires that you only read once for each prompt being produced, e.g. using std::getline(in, line). Obviously, if you don't need a prompt, you don't tie() an std::ostream. Below is a simple program demonstrating the auto-prompt approach (without doing any of the other business):
#include <iostream>
#include <streambuf>
struct prompt
: std::streambuf
{
std::string d_prompt;
std::ostream& d_out;
prompt(std::string const& p, std::ostream& out)
: d_prompt(p)
, d_out(out)
{
}
int sync() {
this->d_out << this->d_prompt << std::flush;
return 0;
}
};
int main()
{
prompt p("prompt>", std::cout);
std::ostream helper(&p);
std::cin.tie(&helper);
for (std::string line; std::getline(std::cin, line); ) {
std::cout << "read '" << line << "'\n";
}
}

C++ reading from .txt file

I have a strange problem that seems to happen when I pass an ifstream by reference.
In my main method, I have created an ifstream, and then I pass it to this read method by reference:
void ArrayStorage::read(ifstream& fin)
{
if (fin.is_open())
{
string input;
getline(fin, input, '\n');
}
else
{
}
}
This should work fine, however, I'm getting the following message in the value of the ifstream:
fin {_Filebuffer={_Set_eback=0xcccccccc _Set_egptr=0xcccccccc ...} } std::basic_ifstream > &
Anyone have any ideas?
EDIT: Code that calls the method:
ifstream fin1("data.txt");
ofstream out1("1-In-SortedRead.txt");
if(!fin1.is_open())
{
cout << "FAIL" << endl;
return 1;
}
ArrayStorage arrayStorage1;
// read in values into data structure
arrayStorage1.read(fin1);