I have the following code:
#include <cstdlib>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <vector>
void tokenize( const std::string& str, char delim, std::vector<std::string> &out )
{
std::size_t start;
std::size_t end = 0;
while (( start = str.find_first_not_of( delim, end )) != std::string::npos )
{
end = str.find( delim, start );
out.push_back( str.substr( start, end - start));
}
}
int main( int argc, char** argv )
{
if ( argc < 2 )
{
std::cout << "Use: " << argv[0] << " file1 file2 ... fileN" << std::endl;
return -1;
}
const char* PATH = getenv( "PATH" );
std::vector<std::string> pathFolders;
int fd = open( "/dev/null", O_WRONLY );
tokenize( PATH, ':', pathFolders );
std::string filePath;
for ( int paramNr = 1; paramNr < argc; ++paramNr )
{
std::cout << "\n" << argv[paramNr] << "\n-------------------" << std::endl;
for ( const auto& folder : pathFolders )
{
switch ( fork() )
{
case -1:
{
std::cout << "fork() error" << std::endl;
return -1;
}
case 0:
{
filePath = folder + "/" + argv[paramNr];
dup2( fd, STDERR_FILENO );
execl( "/usr/bin/file", "file", "-b", filePath.c_str(), nullptr );
break;
}
default:
{
wait( nullptr );
}
}
}
}
return 0;
}
I want to redirect messages like "cannot open `/sbin/file1' (No such file or directory)" to /dev/null, but apparently the error messages aren't redirected to /dev/null.
How can I redirect STDERR to /dev/null?
Edit: I've tested my code with an 'ls' command, and the error message that I've got there was redirected. What I think the issue is here, that the 'file' command doesn't write error message to STDERR.
You are successfully redirecting standard error to /dev/null. The reason you're seeing that message anyway is that file writes its error messages like cannot open `/sbin/file1' (No such file or directory) to standard output, not to standard error. This seems like the one place in their code they use file_printf instead of file_error. And yes, this seems like a serious wart in file, though it's been that way since 1992 with a comment saying it's on purpose, so I wouldn't count on them changing it any time soon.
Related
I've written this code, which it get the repository and look for the files within. it aims to create binary files for each file found so as to write some data inside it later. However, the code is not running as expected. and the binary file are not created this the issue.
the directory has two images, and the output I get is as follows :
Creating bin files
C:\repo\1.bin
Error: failed to create file
Press <RETURN> to close this window...
I really do not know where I miss it. Any advice I'd be glad.
#include <vector>
#include <string>
#include <iostream> // for standard I/O
#include <string> // for strings
#include <iomanip> // for controlling float print precision
#include <sstream> // string to number conversion
#include <fstream>
using namespace std;
void getDir(string d, vector<string> & f)
{
FILE* pipe = NULL;
string pCmd = "dir /B /S " + string(d);
char buf[256];
if( NULL == (pipe = _popen(pCmd.c_str(),"rt")))
{
cout<<"Error"<<endl;
return;
}
while (!feof(pipe))
{
if(fgets(buf,256,pipe) != NULL)
{
f.push_back(string(buf));
}
}
_pclose(pipe);
}
void replaceExt(string& s, const string& newExt) {
string::size_type i = s.rfind('.', s.length());
if (i != string::npos) {
s.replace(i+1, newExt.length(), newExt);
}
}
using namespace std;
int main(int argc, char* argv[])
{
vector<string> files;
string path = "C:\\repo";
getDir(path, files);
vector<string>::const_iterator it = files.begin();
cout<<"Creating bin files "<<endl;
ofstream myOfstream;
while( it != files.end())
{
string fileName = (string) *it;
replaceExt(fileName, "bin");
cout << fileName << '\n';
std::stringstream ss;
ss << fileName << "" ;
myOfstream.open(ss.str(), fstream::binary);
if ( !myOfstream )
{
std::cerr << "Error: failed to create file " << '\n';
break;
}
myOfstream.close();
it++;
}
return 0;
}
First I have to say, if you directory you are looking for doesn't exists or is empty, the program gets locked, it would be nice to have that fixed if making a bigger program.
Then, for your case, I don't see whars the point of that stringstream, so I tried removing that, and changing it by a normal string, removing the last \n character you get from reading the filenames:
cout << fileName << '\n';
string ss = fileName.substr(0, fileName.size() - 1);
myOfstream.open(ss.c_str(), fstream::binary);
if (!myOfstream)
{
hope it helps
I found the issue bro, after debugging ;D
the problem is in the "newline", the string fileName has a "\n" at the end that's whats rise your error. Thus you have to erase it, I ve used this statement fileName.erase(std::remove(fileName.begin(), fileName.end(), '\n'), fileName.end());
and I included algorithm lib.
the working code is as follows :
#include <vector>
#include <string>
#include <iostream> // for standard I/O
#include <string> // for strings
#include <iomanip> // for controlling float print precision
#include <sstream> // string to number conversion
#include <fstream>
#include <algorithm>
using namespace std;
void getDir(string d, vector<string> & f)
{
FILE* pipe = NULL;
string pCmd = "dir /B /S " + string(d);
char buf[256];
if( NULL == (pipe = _popen(pCmd.c_str(),"rt")))
{
cout<<"Error"<<endl;
return;
}
while (!feof(pipe))
{
if(fgets(buf,256,pipe) != NULL)
{
f.push_back(string(buf));
}
}
_pclose(pipe);
}
void replaceExt(string& s, const string& newExt) {
string::size_type i = s.rfind('.', s.length());
if (i != string::npos) {
s.replace(i+1, newExt.length(), newExt);
}
}
using namespace std;
int main(int argc, char* argv[])
{
vector<string> files;
string path = "C:\\repo";
getDir(path, files);
vector<string>::const_iterator it = files.begin();
cout<<"Creating bin files "<<endl;
ofstream myOfstream;
while( it != files.end())
{
string fileName = (string) *it;
replaceExt(fileName, "bin");
cout << fileName << '\n';
fileName.erase(std::remove(fileName.begin(), fileName.end(), '\n'), fileName.end());
std::stringstream ss;
ss << fileName << "" ;
myOfstream.open(ss.str(), fstream::binary);
if ( !myOfstream )
{
std::cerr << "Error: failed to create file " << '\n';
break;
}
myOfstream.close();
it++;
}
return 0;
}
I've never used string or string functions until today and I'm running into a problem that I don't understand. This program as is, should just accept a command line argument, load the file and display it to memory. However it displays it multiple times. I'm pretty sure the for loop is the problem, but it is the same technique as what is used in the programming reference I am using.
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
char* getFile( char* fileName ){
std::fstream inFile( fileName );
if( !inFile ) std::cout << "Could not open " << fileName << ".\n";
else{
inFile.seekg(0,inFile.end);
int len = inFile.tellg();
inFile.seekg(0,inFile.beg);
char* buffer = new char[len];
inFile.read( buffer, len);
inFile.close();
std::cout.write(buffer,len);
return buffer;
}
}
int main(int argc, char** argv){
if(argc != 2) std::cout << "Parameter required\n";
else{
std::string f = getFile( argv[1] );
for( size_t i = f.find( 0x0A, 0 ); i != std::string::npos ; i = f.find( 0x0A, i) ){
std::cout << f.substr(0,i)<<std::endl;
i++;
}
}
}
I see at least one of the problems with my code. I re-wrote the loop as a while loop because it was easier to follow and paid a little more attention to where I am starting and stopping. However it still seems to be printing twice.
int main(int argc, char** argv){
if(argc != 2) std::cout << "Parameter required\n";
else{
std::string f = getFile( argv[1] );
size_t start = 0;
size_t end = 1;
while( end != std::string::npos ){
end = f.find( 0x0A, start );
std::cout << f.substr(start,end)<<std::endl;
start = ( end + 1 );
}
This is because you have two printing statements that are displaying the contents of the file.
The first print statement is this one:
std::cout.write(buffer,len);
The second one is this:
std::cout << f.substr(0,i)<<std::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.
I am an absolute newbie to C++ and have only started to program with it 3 days ago.
I am trying to do the folliwng:
traverse a directory for X.X files (typically .), and for each file, do the following:
Search within the file for a string (findFirst) and then search until another string (findLast) - The files will be HTML format.
In this selection, I want to perform several tasks (yet to write) - but they will be the following:
One of the strings will be the Filename I want to write to. - so extract this field and create an outputfile with this name
Some of the lines will be manufacturer part numbers - extract these and format the output file accordingly
most of it will be description of product. Again - this will be in an HTML construct - so extract this and format the output file.
So far, I have managed to get working the traverse directory, and selecting the start and finish keywords - using some help from the internet.
My problem is here
processFiles(inputFileName, "testing", "finish");
I need the inputFileName to be the name of the traversed filename.
All the examples I have found simply print the filename using cout
I need to pass this into the processFiles function.
Can someone tell me what i need to use? i have tried it->c_Str() and other variations of (*it) and .at, .begin etc
my non printing example is below:
// Chomp.cpp : Defines the entry point for the console application.
//
#include <stdafx.h>
#include <windows.h>
#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <cctype>
#include <algorithm>
#include <vector>
#include <stack>
//std::ifstream inFile ( "c:/temp/input.txt" ) ;
std::ofstream outFile( "c:/temp/output.txt") ;
using namespace std;
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
void openFiles()
{
if (!(outFile.is_open()))
{
printf ("Could not Create Output file\n");
exit(0);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
bool ListFiles(wstring path, wstring mask, vector<wstring>& files)
{
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty())
{
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
return false;
do
{
if (wcscmp(ffd.cFileName, L".") != 0 && wcscmp(ffd.cFileName, L"..") != 0)
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
directories.push(path + L"\\" + ffd.cFileName);
else
files.push_back(path + L"\\" + ffd.cFileName);
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES)
{
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
void processFiles(const wchar_t *inFileName, std::string findFirst,std::string findLast )
{
/*
std::string findFirst = "testing" ;
std::string findLast = "finish" ;
*/
std::string inputLine ;
int lineNum = 0 ;
char buffer[2048];
size_t found = 0;
std::ifstream inFile;
inFile.open (inFileName); // Open The file
if (inFile.is_open())
{
while( std::getline( inFile, inputLine ))
{
++lineNum ;
// printf ("Line len = %d\n ", inputLine.length());
if( (found = inputLine.find(findFirst)) != std::string::npos )
{
std::cout << "###Line " << lineNum << " At Position [ " << found << " ]\n" ;
sprintf_s(buffer, 2048, "[%-5.5d] %s\n", lineNum, inputLine.c_str());
outFile << buffer ;
bool foundLast = 0;
while( std::getline( inFile, inputLine ))
{
++lineNum ;
sprintf_s(buffer, 2048, "[%-5.5d] %s\n", lineNum, inputLine.c_str());
if( (found = inputLine.find(findLast)) != std::string::npos )
{
outFile << buffer ;
break; // Found last string - so stop after printing last line
}
else
outFile << buffer ;
}
}
else
{
// std::cout << "=>" << inputLine << '\n' ;
}
}
}
else
{
printf ("Cant open file \n");
exit(0);
}
inFile.close() ; // Close The file
}
/////////////////////////////////////////////////////////////////////////////////////////////
/// M A I N
/////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
std::ifstream inFile ;
int startLine = 0;
int endLine = 0;
int lineSize = 0;
char buffer[512];
vector<wstring> files; // For Parsing Directory structure
openFiles();
// Start The Recursive parsing of Directory Structure
if (ListFiles(L"C:\\temp", L"*.*", files))
{
for (vector<wstring>::iterator it = files.begin(); it != files.end(); ++it)
{
printf ("Filename1 is %s\n", it->c_str());
printf ("Filename2 is %s\n", files.begin());
outFile << "\n------------------------------\n";
//outFile << it << endl;
wcout << it->c_str() << endl;
outFile << "\n------------------------------\n";
const wchar_t *inputFileName = it->c_str();
// processFiles(inputFileName, "testing", "finish");
// getchar();
}
}
outFile.close();
getchar();
}
Make your processFile accept a wstring, viz:
void processFiles(wstring inFileName, std::string findFirst,std::string findLast )
{
// Make the necessary changes so that you use a wstring for inFileName
}
Call it from main() using:
processFiles(*it, "testing", "finish");
You need to change processFile to use a wifstream instead of a ifstream and you should change all of your narrow strings to use wide strings (or vice versa). Narrow strings and wide strings are not compatible with each other and in order to use one with the other a conversion function must be used such as mbstowcs.
Edit:
You can find an example that should compile here.
I have to write a program that will go through a given folder and use regex_search to find every instance of a certain string. I've got the regex_search working on it's own now, and I'm just trying to figure out how to go through each file. I want to attempt it using directory but am unsure where I would put it. Would I have to put the search through the file into my main method or would I have to create a seperate function outside of the main method for going through each file and call on it within the main method?
This is what I have now. Any tips you guys can give on how to approach this would be greatly appreciated!
Right now the function of it is to read an input text file and output a txt file that shows all the instances and the line number of each apperance. I am not required to see which lines they are on, use a particular file, or make an output file for this program, what I find will simply be printed to the console. I've left what I have now because I'm not sure if I'll checking each indivdual file in a similar fashion just with a different cariable name.
#include <iostream>
#include <regex>
#include <string>
#include <fstream>
#include <vector>
#include <regex>
#include <iomanip>
using namespace std;
int main (int argc, char* argv[]){
// validate the command line info
if( argc < 2 ) {
cout << "Error: Incorrect number of command line arguments\n"
"Usage: grep\n";
return EXIT_FAILURE;
}
//Declare the arguments of the array
string resultSwitch = argv[1];
string stringToGrep = argv[2];
string folderName = argv [3];
regex reg(stringToGrep);
// Validate that the file is there and open it
ifstream infile( inputFileName );
if( !infile ) {
cout << "Error: failed to open <" << inputFileName << ">\n"
"Check filename, path, or it doesn't exist.\n";
return EXIT_FAILURE;
}
while(getline(infile,currentLine))
{
lines.push_back( currentLine );
currentLineNum++;
if( regex_search( currentLine, reg ) )
outFile << "Line " << currentLineNum << ": " << currentLine << endl;
}
infile.close();
}
Reading a directory/folder is operating system dependent. In a UNIX/Linux/MacOS world, you use opendir(), and readdir():
#include <sys/types.h>
#include <dirent.h>
...
DIR *directory = opendir( directoryName );
if( directory == NULL )
{
perror( directoryName );
exit( -2 );
}
// Read the directory, and pull in every file that doesn't start with '.'
struct dirent *entry;
while( NULL != ( entry = readdir(directory) ) )
{
// by convention, UNIX files beginning with '.' are invisible.
// and . and .. are special anyway.
if( entry->d_name[0] != '.' )
{
// you now have a filename in entry->d_name;
// do something with it.
}
}