I have a small code with some file I/O
bool loadConfigFile(std::string configFileName)
{
std::ifstream configFile;
try
{
configFile.open(configFileName, std::ifstream::in);
if(true != configFile.good())
{
throw std::exception("Problem with config file");
}
} catch (std::exception &e)
{
fprintf(stderr, "There was an error while opening the file: %s\n %s\n" , configFileName, e.what());
configFile.close();
}
configFile.close();
return true;
}
And everytime I launch the program without the file provided as a parameter I get some rubbish on output (random characters) or an unexpected error in runtime. What am I doing wrong here ?
"%s" expects an null terminated char array as its input but the code is passing configFileName, which is a std::string. Either use std::string::.c_str() or use std::cerr instead:
std::cerr << "There was an error while opening the file: "
<< configFileName << '\n'
<< e.what() << '\n';
Note that the ifstream constructor has a variant that accepts the filename to open and the destructor will close the stream if it is open so the explicit calls to open() and close() can be omitted:
try
{
std::ifstream configFile(configFileName);
if (!configFile.is_open())
{
throw std::exception("Failed to open '" + configFileName + "'");
}
}
catch (const std::exception& e)
{
// Handle exception.
std::cerr << e.what() << '\n';
return false;
}
Related
I stuck already 2 days on this problem. I'm trying to read compiled shader file with following code:
std::vector<char> ProgramPipeline::readFile(const std::string& filePath)
{
try {
std::ifstream file{ filePath, std::ios::ate | std::ios::binary };
if (!file.is_open())
{
throw std::runtime_error("failed to open file: " + filePath);
}
size_t fileSize = static_cast<size_t>(file.tellg());
std::vector<char> buffer(fileSize);
file.seekg(0);
file.read(buffer.data(), fileSize);
file.close();
return buffer;
}
catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
exit(EXIT_FAILURE);
}
}
Here is an error what I've got from console: failed to open file: vert_shader.spv
When I tried without try{}catch{} the error was:
Unhandled exception at 0x00007FFA22FB466C in Program.exe: Microsoft C++ exception: std::runtime_error at memory location 0x000000D79F14EE48.
and error leads to line: throw std::runtime_error("failed to open file: " + filePath);
I also tried without throw std::runtime_error("failed to open file: " + filePath);
and error leads to
[[noreturn]] static void _Xlength() {
_Xlength_error("vector too long");
}
I convert QFile into FILE* to use some third-part libraries. Here is code:
QTemporaryFile pack200_file;
//Here write something into pack200_file
......
pack200_file.seek(0);
int handle_in = pack200_file.handle();
if (handle_in == -1)
{
qCritical() << "Error reopening " << pack200_file.fileName();
return false;
}
FILE * file_in = fdopen(handle_in, "r");
if(!file_in)
{
qCritical() << "Error reopening " << pack200_file.fileName();
return false;
}
QTemporaryFile qfile_out;
if(!qfile_out.open())
{
qCritical() << "Error opening " << qfile_out.fileName();
return false;
}
int handle_out = qfile_out.handle();
if (handle_out == -1)
{
qCritical() << "Error opening " << qfile_out.fileName();
return false;
}
FILE * file_out = fdopen(handle_out, "w");
if (!file_out)
{
qCritical() << "Error opening " << qfile_out.fileName();
return false;
}
try
{
unpack_200(file_in, file_out);
}
catch (std::runtime_error &err)
{
qCritical() << "Error unpacking " << pack200_file.fileName() << " : " << err.what();
return false;
}
//success
QString finalJarname = .....;
QFile::remove(finalJarname);
QFile::copy(qfile_out.fileName(), finalJarname);
fclose(file_in);
fclose(file_out);
qfile_out.remove(); //Here I got crash
pack200_file.remove();
return true;
I got crash at the line qfile_out.remove();, It seems the remove operation cause it. But I got nothing from trace stack and visual studio do not mention me which code trigger the crash finally.
If I change the code into:
fclose(file_in);
fclose(file_out);
qfile_out.setAutoRemove(false);
pack200_file.setAutoRemove(false);
qfile_out.close();
pack200_file.close();
return true;
it will also crash when return ;
Then I change IDE into QtCreator, it said:
Second Chance Assertion Failed: File
f:\dd\vctools\crt\crtw32\lowio\close.c , Line 47
Expression: (_osfile(fh) & FOPEN)
But I can't find the file f:\dd\vctools\crt\crtw32\lowio\close.c.
How can I localize the source of the crash?
You closed qfile_out's file for it with fclose(). Looks like the Visual C runtime library didn't like that, hence the exception. Suggest you remove the calls to fclose... or avoid mixing Qt and non-Qt file operations.
I open two files, one input and one output. I'd like to handle exceptions for both of them, so by looking at some examples, I made this:
std::ifstream readFile;
readFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
//set the flags for stream bits that indicate failure if ON
std::ofstream writeFile;
writeFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try{
readFile.open(inputFileName);
writeFile.open(outputFileName);
function(readFile, writeFile);
readFile.close();
writeFile.close();
}
catch(std::ifstream::failure &readErr) {
std::cerr << "\n\nException occured when reading a file\n"
<< readErr.what()
<< std::endl;
return -1;
}
catch(std::ofstream::failure &writeErr) {
std::cerr << "\n\nException occured when writing to a file\n"
<< writeErr.what()
<< std::endl;
return -1;
}
This seems like a reasonable solution, but I get a warning:
warning: exception of type 'std::ios_base::failure' will be caught [enabled by default]
catch(std::ofstream::failure &writeErr) {
^
The code does it's thing, but I'm still interested in improving my code. Where have I wronged?
No you can't. The typedef of std::ifstream::failure and std::ofstream::failure are both defined to be std::ios_base::failure.
The best thing you could do is wrap the individual calls with try-catch:
try
{
readFile.open(inputFileName);
}
catch(std::ifstream::failure &readErr)
{
}
try
{
writeFile.open(outputFileName);
}
catch(std::ofstream::failure &writeErr)
{
}
Or check the state of the streams individually in the catch block to see who failed.
The only way to handle exceptions from the two files separately would be to catch the exception and then check the failbit on the streams to determine which of them that failed:
try
{
readFile.open(inputFileName);
writeFile.open(outputFileName);
function(readFile, writeFile);
readFile.close();
writeFile.close();
}
catch (const std::ios_base::failure &err)
{
if (readFile.fail())
{
std::cerr << "\n\nException occured when reading a file\n"
<< readErr.what()
<< std::endl;
}
if (writeFile.fail())
{
std::cerr << "\n\nException occured when writing to a file\n"
<< writeErr.what()
<< std::endl;
}
return -1;
}
string mapFile;
cout << "Enter the file name : ";
cin >> mapFile;
ifstream mapfh;
mapfh.open(mapFile.c_str());
if(mapfh.is_open()) { ... }
else //if board file did not open properly
{
throw;
}
mapfh.close();
I am compiling with g++ in the command line. Whenever I put a file input (even with a full path i.e. /User/...etc./file.txt) it throws an error. I know the input is good, but for whatever reason the open always fails.
This isn't fully portable, but you'll get a more informed output if you interpret the errno,
#include <cerrno>
#include <cstring>
...
if(mapfh.is_open()) { ... }
else //if board file did not open properly
{
std::cout << "error: " << strerror(errno) << std::endl;
throw;
}
And if your policy is to communicate the errors as exceptions then use iostreams native support for the exceptions:
ifstream mapfh;
mapfh.exceptions(std::ios::failbit);
try {
mapfh.open(mapFile.c_str());
...
mapfh.close();
} catch (const std::exception& e) {
std::cout << e.what() << " : " << std::strerror(errno) << std::endl;
}
Is boost::property_tree::ptree can't handle files which use UTF-8 with BOM?
#include <boost/filesystem.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <cstdlib>
#include <iostream>
int main()
{
try
{
boost::filesystem::path path("helper.ini");
boost::property_tree::ptree pt;
boost::property_tree::read_ini(path.string(), pt);
const std::string foo = pt.get<std::string>("foo");
std::cout << foo << '\n';
}
catch (const boost::property_tree::ini_parser_error& e)
{
std::cerr << "An error occurred while reading config file: " << e.what() << '\n';
return EXIT_FAILURE;
}
catch (const boost::property_tree::ptree_bad_data& e)
{
std::cerr << "An error occurred while getting options from config file: " << e.what() << '\n';
return EXIT_FAILURE;
}
catch (const boost::property_tree::ptree_bad_path& e)
{
std::cerr << "An error occurred while getting options from config file: " << e.what() << '\n';
return EXIT_FAILURE;
}
catch (...)
{
std::cerr << "Unknown error \n";
return EXIT_FAILURE;
}
}
helper.ini
foo=str
Output
An error occurred while getting options from config file: No such node
(foo)
What can i do with it? Manually delete BOM from file bedore reading it?
boost 1.53
I'm using this to skip BOM characters:
boost::property_tree::ptree pt;
std::ifstream file("file.ini", std::ios::in);
if (file.is_open())
{
//skip BOM
unsigned char buffer[8];
buffer[0] = 255;
while (file.good() && buffer[0] > 127)
file.read((char *)buffer, 1);
std::fpos_t pos = file.tellg();
if (pos > 0)
file.seekg(pos - 1);
//parse rest stream
boost::property_tree::ini_parser::read_ini(file, pt);
file.close();
}
Yes, easiest option would be to just check if the file starts with BOM and remove it.
You can file a bug against boost (probably should)
You could use boost::iosteams filters to remove BOM from the input stream whenever its found:
filter usage
filter concept
input filter concept with example that can be adapted to drop BOM