Basically I need to open and read a list of files I get from another command.
For each line of output of popen
open a file usen ifstream.open
it compiles and if I put the file name directly it works fine, but it doesn't do anything when using popen output. I've seen questions like this but none of this particular way of giving filenames.
here's the code:
#include <iostream>
#include <sqlite3.h>
#include <stdio.h>
#include <fstream>
using namespace std;
int main () {
ifstream singlefile;
FILE *filelist;
char filename[512];
string progline;
if(!(filelist = popen("find `pwd` -name \"*.js\"", "r"))){
return 1;
}
while( fgets(filename, sizeof(filename), filelist)!=NULL)
{
cout << filename;
singlefile.open(filename, ifstream::in);
while ( singlefile.good() )
{
getline (singlefile,progline);
cout << progline << endl;
}
singlefile.close();
}
pclose(filelist);
return 0;
}
next step would be not open each file inside the loop but to store the file list and then open each file.
Thanks
fgets keeps the trailing newline, resulting in a filename of a non-existing file. Also the stream state is only updated after reading. If I replace the while body with the following code, it works for me:
cout << filename;
size_t len = strlen(filename);
// chop off trailing newline
if (len > 1 && filename[len - 1] == '\n') filename[len - 1] = 0;
singlefile.open(filename, ifstream::in);
while ( getline(singlefile, progline) )
{
cout << progline << endl;
}
singlefile.close();
If you actually want to iterate through a list of files, I'd use Boost.Filesystem, which has a nice C++ interface, works for all filenames (even for those with newlines), and is platform-independent.
If this actually is only an example and your actual command is not find, there is still some room for simplification. Here is a suggestion that uses Boost.Iostreams to get rid of most of the C function calls (it would be great to have a device source reading from a process's standard output, but Boost.Iostreams lacks that):
#include <cstdio>
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>
#include <stdio.h>
#include <boost/noncopyable.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
using namespace std;
namespace io = boost::iostreams;
class Popen: private boost::noncopyable {
public:
explicit Popen(const char* command):
m_stream(popen(command, "r")) {
if (!m_stream) throw runtime_error("popen failed");
}
~Popen() {
pclose(m_stream);
}
FILE* stream() const {
return m_stream;
}
private:
FILE* m_stream;
};
int main() {
Popen pipe_wrapper("find `pwd` -name \"*.cpp\"");
io::file_descriptor_source pipe_device(fileno(pipe_wrapper.stream()), io::never_close_handle);
io::stream<io::file_descriptor_source> pipe_stream(pipe_device, 0x1000, 0x1000);
string filename;
while (getline(pipe_stream, filename)) {
cout << filename << endl;
ifstream file_stream(filename.c_str(), ifstream::in);
string progline;
while (getline(file_stream, progline)) {
cout << progline << endl;
}
}
}
Related
Hey guys I'm new to this,
I managed to make c++ open a random .jpg file from a folder using srand, the files are named sequentially 1-25.
Now I want to print out which file has been chosen by the randomizer every time I run the programm and log it into a .txt file.
The log in the .txt file should look like this:
4
8
5
..and so on, so that it adds the result of the randomizer to a new line each time it gets executed.
This is the code I have so far:
#include <sstream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <fstream>
using namespace std;
int main()
{
srand((unsigned)time(0));
ostringstream oss;
oss << "\"C:\\Users\\etc..";
oss << rand() % 25 + 1;
oss << ".jpg\"";
system(oss.str().c_str());
system("pause");
return 0;
}
See below a complete example how you can achieve what you described.
The function LogToFile uses std::ofstream to open a file in append mode, and write to it.
You can change it if you'd like a different format (e.g. separate by commas instead of newline).
In order to call it with the number I added a variable n to hold the number (rather than streaming it directly into the std::ostringstream).
A side note: better to avoid using namespace std - see here Why is "using namespace std;" considered bad practice?.
The code:
#include <string>
#include <ctime>
#include <fstream>
#include <sstream>
#include <assert.h>
bool LogToFile(std::string const & filename, int n)
{
std::ofstream file;
file.open(filename, std::ios_base::app); // open in append mode
if (!file.is_open())
{
return false;
}
file << n << std::endl;
file.close();
return true;
}
int main()
{
// change according to your needs:
const std::string LOG_FILENAME = "log.txt";
const std::string IMAGE_FOLDER = "C:\\tmp";
srand((unsigned)time(0));
int n = rand() % 25 + 1;
// Add the number to the log file:
bool bRes = LogToFile(LOG_FILENAME, n);
assert(bRes);
std::ostringstream oss;
oss << "\"" << IMAGE_FOLDER << "\\" << n << ".jpg" << "\"";
system(oss.str().c_str());
system("pause");
return 0;
}
i'm trying to write a script in c++ which read a CSV file so i can treat it later .i ve used fstram but the file always fail to open**
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
string filename = "hello.txt"; // could come from command line.
ifstream fin(filename.c_str());
if (!fin.is_open())
{
cout << "Could not open file: " << filename << endl;
return 1;
}
cout<<"khalil"<<endl;
string scores[32];
string names[32];
int iter = 0;
while (iter <= 5)
{
fin >> names[iter] >> scores[iter];
cout << iter <<"\n";
cout<<names[iter]<< "\n";
cout<<scores[iter]<<"\n";
iter++;
}
fin.close();
}
Try using a fully qualified path name, e.g.:
string filename = "C:\\Documents\\hello.txt";It appears your program isn't opening the file because it can't find it.
You can use QFile class to do this operation.
#include <QFile>
#include <QStringList>
#include <QDebug>
int main()
{
QFile file("C\\hello.txt");
if (!file.open(QIODevice::ReadOnly)) {
qDebug()<<file.errorString();
return 0;
}
QStringList firstList, secondList;
while (!file.atEnd()) {
QByteArray line = file.readLine();
firstList.append(line.split(',')[0]);
secondList.append(line.split(',')[1]);
}
qDebug()<<firstList;
qDebug()<<secondList;
}
In my program I use an external function which generates output to me and I don't want it not to be generated by that function alone,
it's possible?
int main()
{
int a;
//I don't want the output of this function
a = function();
//now i want output
cout << "the result is : " << a;
}
Is it possible?
EDIT:
The function is in an external library.
Using only standard C++ where no dup-like functions exist, you could open a temporary std::FILE and std::swap with stdout.
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
// extern "C" int function(); // an assumption
// A helper class to temporarilly redirect the output to stdout to a file and to read
// the content of the file afterwards.
class BufferStdout {
public:
// the collector string is used for collecting the output to stdout
BufferStdout (std::string& collector) :
m_collector(collector),
fp(std::fopen("output.txt", "w"))
{
if(fp == nullptr) throw std::runtime_error(std::strerror(errno));
std::swap(stdout, fp); // swap stdout and the temp file
}
~BufferStdout () {
std::swap(stdout, fp); // swap back
std::fclose(fp);
// read the content of the temp file into m_collector
if(std::ifstream is("output.txt"); is) {
m_collector.append(std::istreambuf_iterator<char>(is),
std::istreambuf_iterator<char>{});
}
std::remove("output.txt"); // cleanup
}
private:
std::string& m_collector;
std::FILE* fp;
};
int main() {
std::string collector; // the string that will contain the output from function()
int a;
{
BufferStdout foo(collector);
a = function();
}
std::cout << "the result is : " << a << '\n';
std::cout << "Collected from function():\n";
std::cout << collector << '\n';
}
Yes it is generally possible but a bit complicated, a similar question is in Suppress output to cout from linked library
In addition to you can redirect stdout before invoking the shared library function and then redirect it again after the use of the shared library function in the however this is also a suboptimal solution. Best solution would be to adapt the shared library
// Cpp program to redirect cout to a file
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
fstream file;
file.open("cout.txt", ios::out);
string line;
// Backup streambuffers of cout
streambuf* stream_buffer_cout = cout.rdbuf();
streambuf* stream_buffer_cin = cin.rdbuf();
// Get the streambuffer of the file
streambuf* stream_buffer_file = file.rdbuf();
// Redirect cout to file
cout.rdbuf(stream_buffer_file);
cout << "This line written to file" << endl;
// Redirect cout back to screen
cout.rdbuf(stream_buffer_cout);
cout << "This line is written to screen" << endl;
file.close();
return 0;
}
Note: The above steps can be condensed into a single step
auto cout_buf = cout.rdbuf(file.rdbuf())
// sets couts streambuffer and returns the old
streambuffer back to cout_buf
source : https://www.geeksforgeeks.org/io-redirection-c/
use
fclose(stdout);
with this function you will suppress any printf inside your libraries.
Of course you can not print other stuff inside your software.
This is what I tried:
#include <iostream>
#include <string>
int main(int argc, char const *argv[]) {
using namespace std;
for (string cin_line; getline(cin, cin_line);) {
cout << cin_line << endl;
}
FILE* pipe = popen("app.exe", "r");
for (string result_line; getline(pipe, result_line);) {
cout << result_line << endl;
}
pclose(pipe);
return 0;
}
It doesn't compile, the result is:
no matching function for call to 'getline(FILE*&, std::__cxx11::string&)'
Second example I've found here: https://stackoverflow.com/a/10702464/393087
But it seems mingw doesn't have pstream included: fatal error: pstream.h: No such file or directory - edit: ok I know, I missed that this is not a GCC library, it is named like it was but this is separate download: http://pstreams.sourceforge.net/
I know how to do it using buffer and get whole output on single line (like here: https://stackoverflow.com/a/478960/393087 ) then explode the line by \n and get my array, but the point here is that I must provide the output as soon as the input comes in.
Also I tried example from here: https://stackoverflow.com/a/313382/393087 - I've added main function to that:
#include <cstdio>
#include <iostream>
#include <string>
int main(int argc, char const *argv[]) {
using namespace std;
FILE * fp ;
if((fp= popen("/bin/df","r")) == NULL) {
// error processing and exit
}
ifstream ins(fileno(fp)); // ifstream ctor using a file descriptor
string s;
while (! ins.eof()){
getline(ins,s);
// do something
}
return 0;
}
This also doesn't compile:
error: variable 'std::ifstream ins' has initializer but incomplete type
ifstream ins(fileno(fp)); // ifstream ctor using a file descriptor
You can't do this:
FILE* pipe = popen("app.exe", "r");
for (string result_line; getline(pipe, result_line);) {
cout << result_line << endl;
}
pclose(pipe);
You need to do this:
#include <boost/noncopyable.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
FILE* pipe = popen("app.exe", "r");
boost::iostreams::file_descriptor_source
source(fileno(pipe), boost::iostreams::never_close_handle);
boost::iostreams::stream<boost::iostreams::file_descriptor_source>
stream(source, 0x1000, 0x1000);
string result_line;
while (getline(stream, result_line)) {
cout << result_line << endl;
}
:)
I am writing a simple program to take in two files. The terminal command line looks like this.
./fileIO foo.code foo.encode
When it runs, the second file is not read in. When I enter
./fileIO foo.code foo.code
it works. I can't seem to figure out why the second one is not opening. Any ideas? Thanks!
#include <fstream>
#include <iostream>
#include <queue>
#include <iomanip>
#include <map>
#include <string>
#include <cassert>
using namespace std;
int main( int argc, char *argv[] )
{
// convert the C-style command line parameter to a C++-style string,
// so that we can do concatenation on it
assert( argc == 3 );
const string code = argv[1];
const string encode = argv[2];
string firstTextFile = code;
string secondTextFile = encode;
//manipulate the first infile
ifstream firstFile( firstTextFile.c_str(), ios::in );
if( !firstFile )
{
cerr << "Cannot open text file for input" << endl;
return 1;
}
string lineIn;
string codeSubstring;
string hexSubstring;
while( getline( firstFile, lineIn ) )
{
hexSubstring = lineIn.substr(0, 2);
codeSubstring = lineIn.substr(4, lineIn.length() );
cout << hexSubstring << ", " << codeSubstring << endl;
}
//manipulate the second infile
ifstream secondFile( secondTextFile.c_str(), ios::in );
if( !secondFile )
{
cerr << "Cannot open text file for input" << endl;
return 1;
}
char characterIn;
while( secondFile.get( characterIn ) )
{
cout << characterIn << endl;
}
return 0;
}
One thing you might want to try is adding the close() call as is standard procedure after you're done using files. Sometimes issues arise with re-opening files if they were not closed properly in a previous run.
firstFile.close();
secondFile.close();
Also, you may try restarting the computer if there is some lingering file handle that hasn't been released.