C++ Read/write file on Unix - c++

I know this is a very specific question. I am compiling a c++ code using g++ compiler on a unix machine.
I have the following one line code to read a text file specified as parameter in C++: test.cc
int main(int argc, char *argv[])
{
ifstream inputfile(argv[1]);
}
Now after compiling with g++, I will call it as:
./test file.txt
But what should I do, if I want to call it as
./test <file.txt
In short how do I do a file read using default input/output

You should check the arguments to main to see if there is an argument given to the program. If it is then you can use that as the file, otherwise you use std::cin.
Here is an example:
void do_something(istream &input)
{
// Read some stuff from the input
}
int main(int argc, char *argv[])
{
if (argc == 1)
do_something(cin);
else if (argc == 2)
do_something(ifstream(argv[1]));
else
{
cout << "Error: Must supply a file\n";
return 1;
}
}
The reason I call another function to read and process the input, is because you can not assign streams, but must use references or pointers. It's also good to put separate tasks in separate functions, because it will increase readability of the code.

When you want to read from standard input, use std::cin instead of opening your own stream.
For example:
std::string s;
std::getline(std::cin, s);

Using < redirects that file to stdin, so you'd get at it via std::cin in c++.

You need instead to read from stdin, da file.
in other words read from the keyboard.
when you pipe stuff in, it will be read as if typed from the keyboard.

You can do what most of the Unix commands do: read from the file if the filename is specified. If the file name is missing read from standard input.

The cin object is already defined in iostream. Just read from cin instead of inputfile.

Perhaps
ifstream &myin;
if (argc>1) {
ifstream* inputfilep = new infstream(argv[1]);
myin = *inputfile;
}
else myin = cin;
/* do your input on myin */

you will need to modify your example to check argc to see if any command line arguments are passed in, as the input redirection is stripped off by the shell so if argc is 0 then read from standard in as given by the other examples, otherwise as your example code.

You don't have to do anything.
Just write your program as if your are reading from the command line.

Related

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();

Providing a file path to an input-dependent program

First off, sorry if the title makes no sense. The nature of my question makes it very hard for me to phrase.
I am working on an assignment for my datastructures class and I am completely and totally brand new to c++ due to only having learned Java at my old school. The project is a weather logger that reads in data from a text file climatedata.txt. My teacher has provided us with a main function in the file (that we are NOT allowed to modify in any way) weatherlog.cpp which is below.
#include <iostream>
#include <fstream>
#include "datalogger.h"
using namespace std;
int main(int argc, char** argv) {
datalogger dl;
if (argc != 2) {
cout << "Usage: " << argv[0] << " <datafile>" << endl;
exit(0);
}
// Read the data
char* datafile = argv[1];
ifstream infile(datafile);
int timestamp;
double temperature;
double windspeed;
while (!infile.eof()) {
infile >> timestamp;
infile >> temperature;
infile >> windspeed;
if (!infile.eof()) {
dl.addData(timestamp, temperature, windspeed);
}
}
// Output the report
dl.printReport();
return(0);
}
Initially I was confused as to why the program would never fully execute until I figured out what argc is in the scope of a main function. It seems that he wants me to provide the text file name while compiling so that argc will be 2 instead of 1 (the value I saw when debugging) so that it can actually execute the rest of the program instead of immediately exiting.
My problem is I'm not sure how to provide the program with the text file location. I've looked all over the internet but since I'm not even sure at which stage to provide the file path I haven't had any success. Is that information supposed to be passed when compiling with g++? After successfully compiling when I'm trying to run the executable? What does the terminal command to do so look like?
So I understand that you need to provide a file name in argv (Comment below if I'm incorrect). argv is an array of arguments passed by the commandline, and argc is the amount of arguments passed (automatically set). To do that simply call the program in terminal like this: ./<progam> <file_name>
Example:
compile just as you would a hello world progam.
Call the program weatherlog climatedata.txt.
If your file has spaces in its name either remove them or do this enclose its name in quotes.
argc stores number of passed in parameters, while argv points to parameters.
if (argc != 2) means checking number of input parameters passed in via Console mode. The first parameter is always the program name. From the second parameter you can pass anything you want. char* datafile = argv[1]; means taking the second parameter as data filename.
In short, open Console mode (CMD on Windows, Terminal on Linux) and type something like: yourprogram C:\path\to\climatedata.txt.

Taking in user input

I am programming a calculator that uses redirection (UNIX) ./calculator < expressions.txt to receive expressions from a file using a while loop in my main:
while(getline(cin, exp) ) {
try {
return the evaluated expressions
}
catch ( error ) { ... }
}
this works fine for me and returns the correct values.
However, I also want my program to take in user input if a file is not redirected (It currently error outs and core dumps). How can I take in user input if a file is not provided and avoid the while loop.
Thank you.
Rather than redirecting stdin why don't you just set up your program to accept command line arguments, one of which could be the file name. Then
int main(int argc, char* argv[]) {
if(argc > 1)
{
// File name is provided. Open the file and read the data
}
else
{
// File name is not provided. Get input from user.
}
return 0;
}
This is a bit trivial, but I'm sure you understand the point. For any more complex command line arg parsing, use a library.
When you are taking input from while like this:
./calculator < expressions.txt
It means you are taking input from STDIN only . So if user does not provide input file, the code will itself take input from user only. So you need not to handle file separately in your code. Just take input from stdin.

How can I detect that input is being redirected in from a file?

I've written a program that takes its first argument and reverses the letters. So, for instance:
revstr cat
Will produce tac.
Now I want this to work when a file is redirected in. So, if filler.txt is a file containing "Now is the time for all good men to come to the aid of their country!", then:
revstr < filler.txt
Should produce:
!yrtnuoc rieht fo dia eht ot emoc ot nem doog lla rof emit eht si woN
But I don't know how to detect that such redirection is occurring!
This is what I've tried - obviously, it's no good. Where am I going wrong?
int main(int argc, char* argv[]) {
string temp,input,output;//store input from file, and get which file//
ofstream out("output.txt");
if(argc == 3)
{
if(ifstream(argv[2]))
{
input = argv[2];
ifstream in(input);
while(in.good())
{
in >> temp;
ReverseWord(temp);
cout << temp << endl;
out << temp << endl;
}
}
else
ReverseWord(argv[2]);
}
else
}
I'm fairly new to C++ and am doing my best to learn.
There are two possible approaches for you (well, you can even support both):
You can accept a file name as command line argument (using a main that accepts arguments), then open an ifstream using this filename as the stream to read from. Users use your program like revstr filename.txt.
You can read your input from std::cin. Then users need to use redirection to pass you the contents of a file. If your program is started using: revstr < filename.txt, then reading from std::cin will read the contents of the file. The program never even sees the filename.
You can support both by reading from an ifstream, if you get an argument, and from cin, if you don't get an argument. The function that does the reading can get the steam passed in as a generic istream&.
You should change your definition of your main() function so that it accepts arguments passed from command line:
int main(int argc, char* argv[])
The first variable will hold the number of command-line arguments provided, the second is a vector whose elements are pointers to NULL-terminated strings. These strings are the command-line arguments themselves. Please keep in mind, that the first string will always be the name of the executable.
For instance, supposing the name of the file to be opened will be passed as the first argument:
int main(int argc, char* argv[])
{
std::string filename;
if (argc > 1)
{
// Oh, there's some command line arguments here...
filename = argv[0];
}
// Go on processing...
}

Is there are a way to find out whether the input is streaming into the program from a file or not?

In Windows, there exists a console trick
someprogram.exe < input.txt
which makes the program to get the input from input.txt whenever there is a input request.
I want my program to behave differently when the input is read from another file. Is there are a way to do that? How?
I don't think so(not sure though), but here is an alternative (error checking omitted):
int main(int argc, char **argv)
{
std::istream * pstream = &std::cin;
std::ifstream fin;
if (argc > 1)
{
fin.open(argv[1]);
pstream = &fin;
}
// use pstream instead of cin
}
Then you pass the name of the file as a command line argument.
Yes, use the function isatty available on most platforms. Looks like it is now called _isatty in windows (not sure why).