I'm building a program that handles input file and output file, with Visual Studio 2012.
I implemented like this:
ifstream inputFile;
ofstream outputFile;
inputFile.exceptions ( ifstream::failbit | ifstream::badbit );
try
{
// some codes here
inputFile.open(inputFileName.c_str());
cout << "Input file opened" << endl;
outputFile.open(outputFileName.c_str());
cout << "Output file opened" << endl;
}
catch (ifstream::failure e)
{
cerr << "Failed to open input file" << endl;
return -1;
}
catch (ofstream::failure e)
{
cerr << "Failed to open output file" << endl;
return -1;
}
And a compile error occurs:
error C2312: 'std::ios_base::failure' : is caught by 'std::ios_base::failure' at line 248
How do I implement try-catch with two sources of exception?
Your problem is that ifstream::failure and ofstream::failure are the same type (inherited to both of them from ios_base),
Since it is the same exception, the compiler complains.
BTW you should catch by const reference to avoid unneeded copies.
As you can see, the types of the exceptions thrown are the same. But, as your checking is done so near the opening of the file, you can do it without exceptions, no? like:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
string inputFileName { "/notexists" };
string outputFileName { "/notexistsandprobablynotwritable" };
ifstream inputFile { inputFileName };
if( !inputFile ) {
cerr << "Failed to open input file" << endl;
return -1;
}
cout << "Input file opened" << endl;
ofstream outputFile { outputFileName };
if( !outputFile ) {
cerr << "Failed to open output file" << endl;
return -1;
}
cout << "Output file opened" << endl;
}
Or, if you really need the exceptions, you can throw different exceptions yourself, at the open site:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
template<typename Stream, typename Exception = typename Stream::failure>
void try_open(Stream& s, string filename) {
s.open(filename);
if( !s )
throw Exception( string("cannot open ")+filename );
}
struct input_exception: ifstream::failure { input_exception(const string& s): ifstream::failure(s) {} };
struct output_exception: ofstream::failure { output_exception(const string& s): ofstream::failure(s) {} };
int main() {
string inputFileName { "/notexists" };
string outputFileName { "/notexistsandprobablynotwritable" };
try {
ifstream inputFile;
try_open<ifstream, input_exception>(inputFile, inputFileName);
cout << "Input file opened" << endl;
ofstream outputFile;
try_open<ofstream, output_exception>(outputFile, outputFileName);
cout << "Output file opened" << endl;
} catch(const output_exception& e) {
cerr << "output exception!\n" << e.what() << "\n";
} catch(const input_exception& e) {
cerr << "input exception!\n" << e.what() << "\n";
} catch(const exception& e) {
cerr << "exception!\n" << e.what() << "\n";
}
}
Related
I'm trying to write and read serialized data to file, but it always breaks when reading specific "PNG" struct, with stored "bed_feet_top.png" from minecraft 1.8.9 textures folder in it, and I can't find a way to get the error. Already tried errno and try and catch, but it always says sucess. It seems that it breaks after and not when reading the buggy "PNG" struct, because the read data is uncorrupted and I can recreate the stored image. I'm using "stb_image" library to read the image data and "zpp_bits" library for serializing the data.
the code i would use:
PNG srcImage; //The "PNG" struct it will break at
unsigned char* buffer = stbi_load("bed_feet_top.png", &image.imageWidth, &image.imageHeight, &image.colorChannels, STBI_rgb_alpha);
if (!buffer)
{
std::cout << "Failed to read image: " + path << std::endl;
return 1;
}
image.pixels = (char*)buffer;
DataBuffer srcBuffer;
srcBuffer.serialize("somePath", "someName", srcImage);
DataManager::writeToFile("someFile.dat", srcBuffer);
DataBuffer dstBuffer;
DataManager::readFromFile("someFile.dat", &dstbuffer);
PNG dstImage = dstBuffer.deserialize<PNG>("somePath", "someName"); //The buggy "PNG" struct data is uncorrupted
the "PNG" struct:
struct PNG
{
int imageWidth, imageHeight, colorChannels;
std::string pixels;
};
the struct I'm storing all serialized data in:
struct DataBuffer
{
std::map<std::string, std::vector<std::byte>> data; //All the serialized data is stored in this map
template<typename T>
void serialize(std::string path, std::string name, T obj)
{
path.append("/");
path.append(name);
serialize(path, obj);
}
template<typename T>
void serialize(std::string fullPath, T obj)
{
if (data.contains(fullPath))
{
std::cout << "Data buffer already contains value with te same path!" << std::endl;
return;
}
try
{
zpp::bits::out out(data[fullPath]);
out(obj).or_throw();
}
catch (const std::exception& error)
{
std::cerr << "Serialization failed with error: " << error.what() << std::endl;
}
catch (...) {
std::cerr << "Serialization failed with unknown error!" << std::endl;
}
}
template<typename T>
T deserialize(std::string path, std::string name)
{
path.append("/");
path.append(name);
return deserialize<T>(path);
}
template<typename T>
T deserialize(std::string fullPath)
{
T obj;
if (!data.contains(fullPath))
{
std::cout << "Data buffer doesn't contain value with the given path!" << std::endl;
return obj;
}
try
{
zpp::bits::in in(data[fullPath]);
in(obj).or_throw();
}
catch (const std::exception& error)
{
std::cerr << "Deserialization failed with error: " << error.what() << std::endl;
}
catch (...) {
std::cerr << "Deserialization failed with unknown error!" << std::endl;
}
return obj;
}
};
The write to file function:
void DataManager::writeToFile(std::string fileName, DataBuffer dataBuffer)
{
std::ofstream ofs(fileName, std::ios::out | std::ios::binary);
if (!ofs.is_open())
{
std::cerr << "Failed to open output file stream!" << std::endl;
return;
}
size_t dataCount = dataBuffer.data.size();
ofs.write((char*)&dataCount, 8);
for (auto const& [key, val] : dataBuffer.data)
{
size_t keySize = key.size();
ofs.write((char*)&keySize, sizeof(keySize));
ofs.write(&key[0], keySize);
size_t entryCount = val.size();
ofs.write((char*)&entryCount, 8);
ofs.write((char*)val.data(), entryCount);
if (!ofs.good()) //ofs.good() never returned false to me
{
std::cerr << "Something went wrong when writing " << key << " to the file!" << std::endl;
break;
}
}
ofs.close();
}
the read from file function:
void DataManager::readFromFile(std::string fileName, DataBuffer* dataBuffer)
{
std::ifstream ifs(fileName, std::ios::in, std::ios::binary);
if (!ifs)
{
std::cerr << "File doesnt exist!" << std::endl;
return;
}
if (!ifs.is_open())
{
std::cerr << "Failed to open input file stream!" << std::endl;
return;
}
size_t dataCount;
ifs.read((char*)&dataCount, 8);
for (size_t i = 0; i < dataCount; i++)
{
size_t keySize;
ifs.read((char*)&keySize, sizeof(keySize));
std::string key;
key.resize(keySize);
ifs.read(&key[0], keySize);
size_t entryCount;
ifs.read((char*)&entryCount, 8);
dataBuffer->data[key].resize(entryCount);
ifs.read((char*)dataBuffer->data[key].data(), entryCount);
if (!ifs.good()) //ifs.good() returns false after it reads the buggy "PNG" struct data
{
std::cerr << "Something went wrong when reading " << key << " from the file!" << std::endl;
break;
}
}
ifs.close();
}
EDIT
I added minimal reproducible example as "Igor Tandetnik" requested.
the minimal reproducible example:
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <string>
#include <iostream>
#include <vector>
#include <fstream>
#include <stb_image.h>
#include "stb_image_write.h"
#include <zpp_bits.h>
struct PNG
{
int imageWidth, imageHeight, colorChannels;
std::string pixels;
};
int main()
{
std::string fileName = "someFile.dat"; //The file we will store the image data in
std::string srcImageName = "bed_feet_top.png"; //Texture from Minecraft 1.8.9 textures folder
std::string dstImageName = "someImage.png"; //The name of image we will create from the read data
//Reading the image data
PNG srcImage;
unsigned char* buffer = stbi_load(srcImageName.c_str(), &srcImage.imageWidth, &srcImage.imageHeight, &srcImage.colorChannels, STBI_rgb_alpha);
if (!buffer)
{
std::cout << "Failed to read image " + srcImageName << std::endl;
return 1;
}
int dataSize = srcImage.imageWidth * srcImage.imageHeight * srcImage.colorChannels;
srcImage.pixels.assign((char*)buffer, dataSize);
//Serializing the image data
std::vector<std::byte> srcData;
try
{
zpp::bits::out out(srcData);
out(srcImage).or_throw();
}
catch (const std::exception& error)
{
std::cerr << "Serialization failed with error: " << error.what() << std::endl;
}
catch (...) {
std::cerr << "Serialization failed with unknown error!" << std::endl;
}
//Writing the image data to file
std::ofstream ofs(fileName, std::ios::out | std::ios::binary);
if (!ofs.is_open())
{
std::cout << "Failed to open output file stream!" << std::endl;
return 1;
}
size_t srcEntryCount = srcData.size();
ofs.write((char*)&srcEntryCount, 8);
ofs.write((char*)srcData.data(), srcEntryCount);
if (!ofs.good())
{
std::cerr << "Something went wrong when writing" << srcImageName << " to the file!" << std::endl;
ofs.close();
return 1;
}
ofs.close();
//Reading the image data from file
std::ifstream ifs(fileName, std::ios::in, std::ios::binary);
if (!ifs)
{
std::cout << "File doesnt exist!" << std::endl;
return 1;
}
if (!ifs.is_open())
{
std::cout << "Failed to open input file stream!" << std::endl;
return 1;
}
std::vector<std::byte> dstData;
size_t dstEntryCount;
ifs.read((char*)&dstEntryCount, 8);
dstData.resize(dstEntryCount);
ifs.read((char*)dstData.data(), dstEntryCount);
if (!ifs.good())
{
std::cerr << "Something went wrong when reading " << srcImageName << " from the file!" << std::endl;
ifs.close();
return 1; //If you comment this line you will see it will recreate the image from the read data just fine
}
ifs.close();
//Deserializing the read image data
PNG dstImage;
try
{
zpp::bits::in in(dstData);
in(dstImage).or_throw();
} catch (const std::exception& error)
{
std::cerr << "Deserialization failed with error: " << error.what() << std::endl;
} catch (...) {
std::cerr << "Deserialization failed with unknown error!" << std::endl;
}
//Recreating the image from the read image data
stbi_write_png(dstImageName.c_str(), dstImage.imageWidth, dstImage.imageHeight, dstImage.colorChannels, dstImage.pixels.c_str(), dstImage.imageWidth * sizeof(int));
}
I'm caling the objects src and dst, because I don't know how to call them shortly before and after serialization. :D
I am wondering how to make a lambda in C++ for this function and the type has to be void
void setIO(string s){
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
}
You can specify the type like so:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
const string FILE_NAME = "test.txt";
auto f = [](string const &name) -> void {
ofstream file;
file.open(name);
file << "junk\n" << "junk2" << endl;;
file.close();
};
f(FILE_NAME);
ifstream inputFile(FILE_NAME);
if (inputFile.is_open()) {
cout << "File is open." << endl;
string line;
while (getline(inputFile, line))
cout << line << '\n';
cout << flush;
inputFile.close();
} else
cerr << "Error opening file." << endl;
return EXIT_SUCCESS;
}
However, lambda functions can deduce the return type, so you can leave out -> void.
auto f = [](string const &name) {
ofstream file;
file.open(name);
file << "junk\n" << "junk2" << endl;;
file.close();
};
The equivalent way to create a lambda would be:
auto f = [](string s) -> void {
//freopen((s+".in").c_str(),"r",stdin);
//freopen((s+".out").c_str(),"w",stdout);
std::cout<<"inside lambda"<<std::endl;
//some other code here
};
Now you can use/call this as:
f("passing some string");
I need to create a program that reads a file, pushes the content into a stack, then writes that content in reverse to another file. I don't understand why my file isn't being found or outputting. Here is my code:
#include "stdafx.h"
#include <iostream>
#include <stack>
#include <fstream>
#include <string>
int main() {
std::stack<char>charStack;
std::fstream file;
std::fstream revFile;
std::string fileName;
std::cout << "Enter the name of the file you want to open." << std::endl;
std::cin >> fileName;
file.open(fileName);
std::cout << "Adding input from file to stack." << std::endl;
char ch;
file >> std::noskipws;
while (file >> ch) {
std::cout << ch;
charStack.push(ch);
}
file.close();
revFile.open("newFile.txt");
std::cout << std::endl;
std::cout << "Reversing stack and writing to file." << std::endl;
while (!charStack.empty()) {
char i = charStack.top();
revFile << i;
charStack.pop();
}
revFile.close();
revFile.open("newFile.txt");
std::cout << "Here is the original file reversed." << std::endl;
std::string line;
if (revFile.is_open()) {
while (std::getline(revFile, line)) {
std::cout << line;
}
revFile.close();
}
else std::cout << "Unable to open file" << std::endl;
revFile.close();
return 0;
}
I'm unsure if I need to add an empty .txt file to write to or if this should generate one for me. Any help would be appreciated.
You need to change the file opening statements to be:
revFile.open("newFile.txt",ios::out); //for output
and
revFile.open("newFile.txt",ios::in); //for input
other than that, you just need to correct this line to get a correct printing of the file contents after reversing.
std::cout << line;
Make it:
std::cout << line << "\n";
I wanna write in file and then read from it and print the result
Here is my code
#include<iostream>
#include<fstream>
using namespace std;
int main(int argc,char* argv[]){
int x,y;
ofstream fd1(argv[1]);
ifstream fd2(argv[1]);
cin>>x;
fd1<<x;
fd2>>y;
cout<<"just read "<<y<<endl;
fd1.close();
fd2.close();
return 0;
}
What's wrong with it? I input 123 it outputs "just read -1078463800"
Even if you can open both in read & write, this write operation is buffered, which means that it may not be written to disk unless you flush the stream (or you close the file).
Of course the code below works perfectly:
#include<iostream>
#include<fstream>
using namespace std;
int main(int argc,char* argv[]){
int x,y;
ofstream fd1(argv[1]);
cin>>x;
fd1<<x;
fd1.close();
ifstream fd2(argv[1]);
if (fd2.good())
{
cout << "read OK" << endl;
}
fd2>>y;
cout<<"just read "<<y<<endl;
fd2.close();
return 0;
}
The fd2>>y statement is failing because there is nothing to read from the file yet. std::ofstream buffers its output, and you haven't flushed the buffer to the file on disk before trying to then read from the file.
std::ofstream flushes its buffer when:
a new line is written.
its flush() method is called, either directly or when std::flush or std::endl is streamed to it.
Try this:
fd1 << x << flush;
Or:
fd1 << x;
fd1.flush();
On a side note, you really should be checking for errors along the way. The std::ofstream and std::ifstream constructors could fail to create/open the file. The << and >> operators could fail to write/read values. All of those operations can report errors that you can check for. For example:
#include <iostream>
#include <fstream>
int main(int argc, char* argv[])
{
int x, y;
std::ofstream fd1(argv[1]);
std::ifstream fd2(argv[1]);
if (!fd1.is_open())
{
std::cout << "cannot create output file" << std::endl;
}
else if (!fd2.is_open())
{
std::cout << "cannot open input file" << std::endl;
}
else if (!(std::cin >> x))
{
std::cout << "invalid input" << std::endl;
}
else if (!(fd1 << x << std::flush))
{
std::cout << "cannot write to output file" << std::endl;
}
else if (!(fd2 >> y))
{
std::cout << "cannot read from input file" << std::endl;
}
else
{
std::cout << "just read " << y << std::endl;
}
return 0;
}
Alternatively:
#include <iostream>
#include <fstream>
int main(int argc, char* argv[])
{
int x, y;
std::ofstream fd1;
std::ifstream fd2;
fd1.exceptions(std::ofstream::failbit);
fd2.exceptions(std::ifstream::failbit);
std::cin.exceptions(std::ifstream::failbit);
try
{
fd1.open(argv[1]);
fd2.open(argv[1]);
std::cin >> x;
fd1 << x << std::flush;
fd2 >> y;
std::cout << "just read " << y << std::endl;
}
catch (const std::ios_base::failure &e)
{
std::cout << "error! " << e.what() << std::endl;
}
return 0;
}
#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
using namespace std;
int main()
{
string temp;
ifstream inFile;
ofstream outFile;
inFile.open("ZRMK Matched - 010513.txt");
outFile.open("second.txt");
while(!inFile.eof()) {
getline(inFile, temp);
if (temp != "") {
getline(inFile, temp);
outFile << temp;
}
}
cout << "Data Transfer Finished" << endl;
return 0;
}
I'm having difficulty getting this to work. When I execute the program it cycles for awhile and then terminates without finishing -- it doesn't output any lines of text to the output file. Any help would be appreciated.
Are you trying to copy every line?
while(std::getline(inFile, temp)) {
outFile << temp << "\n";
}
Are you trying to copy every non-blank line?
while(std::getline(inFile, temp)) {
if(temp != "")
outFile << temp << "\n";
}
Are you trying to copy every 2nd non-blank line?
int count = 0;
while(std::getline(inFile, temp)) {
if(temp == "")
continue;
count++;
if(count % 2)
outFile << temp << "\n";
}
Are you simply trying to copy the entire file?
outFile << inFile.rdbuf();
You should use a mode to open files : see std::ios_base::openmode
And don't forget to close the streams you open !
You can even try catch your code to understand the problem if an exception occurred.
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
try {
fstream inFile;
fstream outFile;
// open to read
inFile.open("ZRMK Matched - 010513.txt", ios_base::in);
if (!inFile.is_open()) {
cerr << "inFile is not open ! " << endl;
return EXIT_FAILURE;
}
// Open to append
outFile.open("second.txt", ios_base::app);
if (!inFile.is_open()) {
cerr << "inFile is not open ! " << endl;
return EXIT_FAILURE;
}
string line;
while(getline(inFile, line)) {
if (!line.empty()) {
outFile << line << endl;
}
}
if (outFile.is_open()) {
outFile.close(); // Close the stream if it's open
}
if (inFile.is_open()) {
inFile.close(); // Close the stream if open
}
cout << "Data Transfer Finished" << endl;
return EXIT_SUCCESS;
} catch (const exception& e) {
cerr << "Exception occurred : " << e.what() << endl;
}
return EXIT_FAILURE;
}