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");
}
Related
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;
}
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
ifstream f;
f.open(fileName);
if ( f.fail() )
{
// I need error message here, like "File not found" etc. -
// the reason of the failure
}
How to get error message as string?
Every system call that fails update the errno value.
Thus, you can have more information about what happens when a ifstream open fails by using something like :
cerr << "Error: " << strerror(errno);
However, since every system call updates the global errno value, you may have issues in a multithreaded application, if another system call triggers an error between the execution of the f.open and use of errno.
On system with POSIX standard:
errno is thread-local; setting it in one thread does not affect its
value in any other thread.
Edit (thanks to Arne Mertz and other people in the comments):
e.what() seemed at first to be a more C++-idiomatically correct way of implementing this, however the string returned by this function is implementation-dependant and (at least in G++'s libstdc++) this string has no useful information about the reason behind the error...
You could try letting the stream throw an exception on failure:
std::ifstream f;
//prepare f to throw if failbit gets set
std::ios_base::iostate exceptionMask = f.exceptions() | std::ios::failbit;
f.exceptions(exceptionMask);
try {
f.open(fileName);
}
catch (std::ios_base::failure& e) {
std::cerr << e.what() << '\n';
}
e.what(), however, does not seem to be very helpful:
I tried it on Win7, Embarcadero RAD Studio 2010 where it gives "ios_base::failbit set" whereas strerror(errno) gives "No such file or directory."
On Ubuntu 13.04, gcc 4.7.3 the exception says "basic_ios::clear" (thanks to arne)
If e.what() does not work for you (I don't know what it will tell you about the error, since that's not standardized), try using std::make_error_condition (C++11 only):
catch (std::ios_base::failure& e) {
if ( e.code() == std::make_error_condition(std::io_errc::stream) )
std::cerr << "Stream error!\n";
else
std::cerr << "Unknown failure opening file.\n";
}
Following on #Arne Mertz's answer, as of C++11 std::ios_base::failure inherits from system_error (see http://www.cplusplus.com/reference/ios/ios_base/failure/), which contains both the error code and message that strerror(errno) would return.
std::ifstream f;
// Set exceptions to be thrown on failure
f.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
f.open(fileName);
} catch (std::system_error& e) {
std::cerr << e.code().message() << std::endl;
}
This prints No such file or directory. if fileName doesn't exist.
You can also throw a std::system_error as shown in the test code below. This method seems to produce more readable output than f.exception(...).
#include <exception> // <-- requires this
#include <fstream>
#include <iostream>
void process(const std::string& fileName) {
std::ifstream f;
f.open(fileName);
// after open, check f and throw std::system_error with the errno
if (!f)
throw std::system_error(errno, std::system_category(), "failed to open "+fileName);
std::clog << "opened " << fileName << std::endl;
}
int main(int argc, char* argv[]) {
try {
process(argv[1]);
} catch (const std::system_error& e) {
std::clog << e.what() << " (" << e.code() << ")" << std::endl;
}
return 0;
}
Example output (Ubuntu w/clang):
$ ./test /root/.profile
failed to open /root/.profile: Permission denied (system:13)
$ ./test missing.txt
failed to open missing.txt: No such file or directory (system:2)
$ ./test ./test
opened ./test
$ ./test $(printf '%0999x')
failed to open 000...000: File name too long (system:36)
The std::system_error example above is slightly incorrect. std::system_category() will map the error codes from system's native error code facility. For *nix, this is errno. For Win32, it is GetLastError(). ie, on Windows, the above example will print
failed to open C:\path\to\forbidden: The data is invalid
because EACCES is 13 which is the Win32 error code ERROR_INVALID_DATA
To fix it, either use the system's native error code facility, eg on Win32
throw new std::system_error(GetLastError(), std::system_category(), "failed to open"+ filename);
Or use errno and std::generic_category(), eg
throw new std::system_error(errno, std::generic_category(), "failed to open"+ filename);
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;
}