This question already has answers here:
c popen won't catch stderr
(2 answers)
Closed 6 years ago.
I have a directory that when i run a ls command on, I know that it spits out an error like so:
ls: reading directory /mydir: Input/output error
I want to be able to detect that there was an IO error in my code.
This is what i've tried:
void readLs(const std::string& name)
{
stringstream ss;
ss << "ls " << name;
FILE* apipe = popen(ss.str().c_str(), "r");
if(apipe == NULL)
{
cout << "Error opening popen" << endl;
return;
}
char line[256];
cout << __FILE__ << " " << __LINE__ << endl; //This is line 46
while ( fgets( line, 256 , apipe) )
{
string temp(line);
cout << "This is line: " << temp << endl;
memset(line, 0, 256);
}
cout << __FILE__ << " " << __LINE__ << endl; //This is line 53
pclose(apipe);
}
test.cpp 46
ls: reading directory /mydir: Input/output error
test.cpp 53
The error message prints out to the screen but i don't get the error message when reading from the pipe.
Thanks,
Conversely, reading from the stream reads the command's
standard output
http://man7.org/linux/man-pages/man3/popen.3.html
You are reading the standard input of the invoked program, which is empty. The error message is written to the standard output. Try executing ls 2>&1.
Related
I am a beginner of c++ and find this question and code online, was trying to make it ok to read not only the file he gave but also any txt file but it shows some problem and I have no idea how to fix
the text file is just like regular text file, not an HTML format txt file
#include <iostream>
#include <fstream>
#include <map>
using namespace std;
istream findParagraph(istream& is, string& word)
{
cout << "<br>" << endl;
}
int main(int argc, char* argv[])
{
argv[1] = "The Republic, by Plato.txt";
ifstream infile(argv[1]);
char ch = 0;
ofstream out("title.html");
out << "<html>" << endl
<< "<head>" << endl
<< "<title>" << argv[1] << "</title>" << endl
<< "</head>" << endl
<< "<body>" << endl;
typedef map<string, unsigned> dictionary_type;
dictionary_type words;
string word;
while (findParagraph(infile, word))
++words[word];
out << "</body>" << endl << "</html>";
} //end main
1>C:\Users\User\source\repos\txt2html\txt2html\txt2html.cpp(15,40): error C2440: '=': cannot convert from 'const char [27]' to 'char *'
You want a basic program that converts a textfile to a minimum html file. You can pass the filename of the text file as parameter to your program.
If the name of your executable program would be "convert", then you can invoke your program with "convert input.txt"
The first parameter that you enter on the command line will appear in argv[1], the 2nd in argv[2] and so on. argv[0] contains the name of the program itself.
So please adapt the handling of the argv parameter. By the way, you could also give the name of the output html file as additional parameter and user argv[2] as output file name. argc would then be 3.
After opening all files and checking for errors, we will first write initial header information to the output html file.
Then we use the std::getline() function to read the source file line by line, until it is completely read.
For each line we read, we will output the plain text to the html file and add a line break "< br >".
At the end, we write the closing tags and that's it.
Please see the attached skelleton example program, which you can use to develop your ideas further.
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
int main(int argc, char *argv[])
{
// Filename is parameter
// Check if program has been invoked with on parameter
if (argc == 2) {
// Parameter is filename. Try to open the input text file
std::ifstream textFile(argv[1]);
// File could be opened
if (textFile) {
// Now open the output file. Becuase, if this cannot be opened then no need to do further steps
std::ofstream htmlFile("title.html");
if (htmlFile) {
// All files are open. Start to build the output
// Start writing the header
htmlFile << "<html>" << '\n' << "<head>" << '\n' <<"<title>" << argv[1] << "</title>" << '\n' << "</head>" <<
"<body>" << '\n';
// Write the body
// Frist read a complete line
std::string line{};
while (std::getline(textFile, line)) {
// Write the line and append a <br>
htmlFile << line << "<br>" << '\n';
}
// End of body
htmlFile << "</body>" << '\n' << "</html>" << '\n';
}
else {
// Error. HTML file could not be opend
std::cerr << "Could not open output HTML file 'title.html'\n";
}
}
else {
// Error. input text file could not be opend
std::cerr << "Could not open input text file '" << argv[1] << "'\n";
}
}
else {
// // Error, program has not been invoked correctly
std::cerr << "Nof Filename given. Invoke this program ("<< argv[0] << ") with 'file name' as parameter\n";
}
return 0;
}
I have two processes. One writes to a file, one has to read from it (At the same time..). So there's two fstreams open at a given time for the file (Although they may be in different processes).
I wrote a simple test function to crudely implement the sort of functionality I need:
void test_file_access()
{
try {
std::string file_name = "/Users/xxxx/temp_test_folder/test_file.dat";
std::ofstream out(file_name,
std::ios_base::out | std::ios_base::app | std::ios_base::binary);
out.write("Hello\n", 7);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::array<char, 4096> read_buf;
std::ifstream in(file_name,
std::ios_base::in | std::ios_base::binary);
if (in.fail()) {
std::cout << "Error reading file" << std::endl;
return;
}
in.exceptions(std::ifstream::failbit | std::ifstream::badbit);
//Exception at the below line.
in.read(read_buf.data(), read_buf.size());
auto last_read_size = in.gcount();
auto offset = in.tellg();
std::cout << "Read [" << read_buf.data() << "] from file. read_size = " << last_read_size
<< ", offset = " << offset << std::endl;
out.write("World\n", 7);
std::this_thread::sleep_for(std::chrono::seconds(1));
//Do this so I can continue from the position I was before?
//in.clear();
in.read(read_buf.data(), read_buf.size());
last_read_size = in.gcount();
offset = in.tellg();
std::cout << "Read [" << read_buf.data() << "] from file. read_size = " << last_read_size
<< ", offset = " << offset << std::endl;
//Remove if you don't have boost.
boost::filesystem::remove(file_name);
}
catch(std::ios_base::failure const & ex)
{
std::cout << "Error : " << ex.what() << std::endl;
std::cout << "System error : " << strerror(errno) << std::endl;
}
}
int main()
{
test_file_access();
}
Run, and the output is like this:
Error : ios_base::clear: unspecified iostream_category error
System error : Operation timed out
So two questions,
What is going wrong here? Why do I get an Operation timed out error?
Is this an incorrect attempt to do what I need to get done? If so, what are the problems here?
You write into this file 7 bytes, but then try to read 4096 bytes. So in stream will read only 7 bytes and throw an exception as requested. Note that if you catch this exception the rest of the code will be executed correctly, e.g. last_read_size will be 7 and you can access those 7 bytes in buffer.
I need to execute multiple times a FORTRAN program, that requires the user to insert 4 numeric values each time.
I found a solution to make this automatically with a Python script...this script basically creates at each iteration a .sh file containing the following lines (a.out is the name of the FORTRAN program I have to execute automatically)
./a.out<<EOF
param01
param02
param03
param04
EOF
makes it executable, and executes it.
So, I'm trying to do the same in C++...I wrote something like
int main()
{
long double mass[3] = {1.e+10,3.16e+10,1.0e+11};
double tau[3] = {0.5,0.424,0.4};
double nu[3] = {03.0,4.682,10.0};
long double Reff[3] = {1.0e+3,1.481e+3,3.0e+3};
int temp=0;
for (int i=0; i<3; i++)
{
ofstream outfile("shcommand.sh");
outfile << "./a.out<<EOF" << endl << mass[i] << endl << nu[i] << endl << Reff[i] << endl << tau[i] << endl << "EOF" << endl;
temp=system("chmod +x shcommand.sh");
temp=system("./shcommand.sh");
}
return 0;
}
but when I run my C++ program, I get the following error message
sh: 1: ./shcommand.sh: Text file busy
sh: 1: ./shcommand.sh: Text file busy
sh: 1: ./shcommand.sh: Text file busy
Has it something to do with the C++ program trying to modify the .sh file before the previous iteration is finished?
I looked online, and I seemed to understand the system() command onlyreturns after the command has been completed...
You are trying to run an open file, which isn't such a good idea. Close it before chmodding/running it:
for (int i=0; i<3; i++)
{
{
ofstream outfile("shcommand.sh");
outfile << "./a.out<<EOF" << endl << mass[i] << endl << nu[i] << endl << Reff[i] << endl << tau[i] << endl << "EOF" << endl;
// the file is closed when outfile goes out of scope
}
temp=system("chmod +x shcommand.sh");
temp=system("./shcommand.sh");
}
Incidentally, all this shell mess can be avoided by writing straight to the standard input of your program (e.g. with popen):
for (int i=0; i<3; ++i) {
FILE *fd = popen("./a.out", "w");
assert(fd!=NULL); // do proper error handling...
fprintf(fd, "%Lf\n%f\n%Lf\n%f\n", mass[i], nu[i], Reff[i], tau[i]);
fclose(fd);
}
It seems because the shell cannot read the script because it is still opened by your program.
Try adding outfile.close(); before calling system().
I am trying to read a las file larger then 2GBs (about 15GBs) but ios::fail() flag becomes true in 345th byte. Here is the code below.
void Foo()
{
char* filename = "../../../../../CAD/emi/LAS_Data/AOI.las";
ifstream m_file (filename);
char c;
int count = 0;
if (m_file.is_open())
{
while ( m_file.good() )
{
m_file.get(c);
cout << c << endl;
count++;
}
// Check State
if(m_file.fail())
cout << "File Error: logical error in i/o operation." << endl;
if(m_file.eof())
cout << "Total Bytes Read: " << count << endl;
m_file.close();
}
else
{
cout << "File Error: Couldn't open file: " << endl;
}
}
And the output is:
...
File Error: logical error in i/o operation.
Total Bytes Read: 345
What am I missing?
I'm going to guess that you're using Windows. Windows has a quirk that a Control-Z marks the end of a text file, no matter how large the file actually is. The solution is to open the file in Binary mode.
ifstream m_file (filename, std::ios::binary);
I have a C++ program that reads a config file and gets the directories.
What I want to do now is to execute an .exe program using the directory settings from the config file.
Here is a piece of my code:
int main(){
ConfigFile cfg("htbaseconfig.properties");
bool exists = cfg.keyExists("backuplocation");
exists = cfg.keyExists("logdir");
exists = cfg.keyExists("execdir");
exists = cfg.keyExists("fulldir");
exists = cfg.keyExists("incdir");
exists = cfg.keyExists("appdir");
std::string bkploc = cfg.getValueOfKey<std::string>("backuplocation");
std::cout << "Backup Location: " << bkploc << "\n";
std::string bkplogdir = cfg.getValueOfKey<std::string>("logdir");
std::cout << "Log Location: " << bkplogdir << "\n";
std::string bkpexec = cfg.getValueOfKey<std::string>("execdir");
std::cout << "Exec Directory: " << bkpexec << "\n";
std::string bkpfulldir = cfg.getValueOfKey<std::string>("fulldir");
std::cout << "Full Directory: " << bkpfulldir << "\n";
std::string bkpappdir = cfg.getValueOfKey<std::string>("appdir");
std::cout << "Real app Directory: " << bkpappdir << "\n\n\n";
for( ; ; ) {
Sleep(6000);
ShellExecute(NULL, L"open", , L"C:\\teste.htm", NULL,SW_SHOWNORMAL);
}
std::cin.get();
return (0);}
Inside the ShellExecute, I wanted to execute the following line parsing the config options:
$execdir/program.exe $logdir/log.txt $bkpappdir $bkploc
How do I do this? I want to execute my program with the variables I get on std::cout.
You must pass to ShellExecute, instead of the second NULL, a string (c string, a char[]) that contains all parameters, like if you are passing them to the command line.
So Will be something like
ShellExecute(NULL, L"open", , L"C:\\teste.htm", "option=param option2=param2",SW_SHOWNORMAL);
Depends on how you parse them (or how they are parsed) from the other exe file