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

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

Related

C++ input redirection causing error while file arguments work

When I specify an input file as a file argument, like so:
./asm ex1_in
everything works as it should!
However, when I specify an input file using redirection, like so:
./asm < ex1_in
the program throws the error it is supposed to throw when the input file is corrupt or doesn't exist.
This is the part of the code that handles input and file arguments:
int main(int argc, char * argv []) {
ifstream InFile(argv[1], ios::in);
if (!(InFile.is_open())) { /* check file */
fprintf (stderr, "The input file cannot be open or cannot be read. \n");
return 2;
}
if (InFile.is_open()) {
//some stuff
InFile.close();
}
//other stuff
}
I would like to be able to keep using ifstream, as it is very helpful for the rest of the program.
Also, the program is supposed to accept input directly on stdin if no file argument is supplied. Currently, if no file arguments are supplied, it throws the same error, instead of looking for user input.
EDIT: I added a line in main to try to see what's going on, and it looks like when input redirection is used, the program doesn't see argv[1] or anything after it.
cout << argv[0] << " " << argv[1] << " " << argv[2];
prints out only ./asm.
When input redirection isn't used, it prints out:
./asm ex1_in my1_out
You are trying to open argv[1] as a file every time you run the program.
In the first case, argv has a lenght of two (the executable name and the filename) so it opens and does what it needs to do normally, but when you run it redirecting the file to the stdin, argv just contains the executable name, and since argv[1] is a C-style string, it will read everything until it finds a null byte, then pass whatever it read to the std::ifstream constructor, failing each time.
You should use argc to know the number of arguments passed, and use either the file or stdin depending on the number of arguments.

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.

How can you open a file that the user specifies on the command line?

Suppose you want to allow the user to specify a file to open on the command line. How can this be achieved if the user will enter data such as:
/User/desktop/input.txt
How can I then convert this directory into something that the program actually opens/reads?
std::ifstream is the way.
std::ifstream file(your_file_path);
if (!file) { return; } // check the file
std::string line;
while (getline(file, line)) { /* do some process on line */ }
The parameter argc holds the count of command line arguments. If you don't pass any arguments, it's 1 (argv[0] is just the name of your executable). Otherwise its the count of command line arguments + 1.
#include <fstream>
int main (int argc, char **argv){
if(argc>1){
std::ifstream a(argv[1]); // first argument
if(a){
//file opened
}
}
}
To start this program, you would type on your command-line:
nameOfYourExecutable.exe /User/desktop/input.txt
See also here for further informations.
Just open("path",permissions,flags) will work fine.. and you can read or write using the file descriptor.
What is the deference if you get it from the command line argument, or hard-code it in your program?
just use open().

C++ Read/write file on Unix

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.

C++ length of file and vectors

Hi I have a file with some text in it. Is there some easy way to get the number of lines in the file without traversing through the file?
I also need to put the lines of the file into a vector. I am new to C++ but I think vector is like ArrayList in java so I wanted to use a vector and insert things into it. So how would I do it?
Thanks.
There is no way of finding the number of lines in a file without reading it. To read all lines:
1) create a std::vector of std::string
3 ) open a file for input
3) read a line as a std::string using getline()
4) if the read failed, stop
5) push the line into the vector
6) goto 3
You would need to traverse the file to detect the number of lines (or at least call a library method that traverse the file).
Here is a sample code for parsing text file, assuming that you pass the file name as an argument, by using the getline method:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
int main(int argc, char* argv[])
{
std::vector<std::string> lines;
std::string line;
lines.clear();
// open the desired file for reading
std::ifstream infile (argv[1], std::ios_base::in);
// read each file individually (watch out for Windows new lines)
while (getline(infile, line, '\n'))
{
// add line to vector
lines.push_back (line);
}
// do anything you like with the vector. Output the size for example:
std::cout << "Read " << lines.size() << " lines.\n";
return 0;
}
Update: The code could fail for many reasons (e.g. file not found, concurrent modifications to file, permission issues, etc). I'm leaving that as an exercise to the user.
1) No way to find number of lines without reading the file.
2) Take a look at getline function from the C++ Standard Library. Something like:
string line;
fstream file;
vector <string> vec;
...
while (getline(file, line)) vec.push_back(line);
Traversing the file is fundamentally required to determine the number of lines, regardless of whether you do it or some library routine does it. New lines are just another character, and the file must be scanned one character at a time in its entirety to count them.
Since you have to read the lines into a vector anyways, you might as well combine the two steps:
// Read lines from input stream in into vector out
// Return the number of lines read
int getlines(std::vector<std::string>& out, std::istream& in == std::cin) {
out.clear(); // remove any data in vector
std::string buffer;
while (std::getline(in, buffer))
out.push_back(buffer);
// return number of lines read
return out.size();
}