I have sought to discover the cause of unwanted trailing end-data in a file I am writing specific data into and do not believe I have made errors in writing to the file.
The output looks like:
building room_numbr capacity
packard | 101 | 500 |
painter | 514 | 10 |
ÿÿÿÿÿÿÿÿÿÿ | Attempt to seek file pointer error
The Attempt to seek file pointer error is normal as it represents a thrown exception when attempting to move the file pointer on an invalid stream. However, the ÿÿÿÿÿÿÿÿÿÿ is not normal nor expected in a fixed size file format using either 10 or 20 bytes to write data.
Create file here:
BinarySearchFile::BinarySearchFile(std::string file_name){
// concatenate extension to fileName
file_name += ".dat";
// form complete table data filename
data_file_name = file_name;
// create or reopen table data file for reading and writing
binary_search_file.open(data_file_name, std::ios::out | std::ios::in | std::ios::app);
if(!binary_search_file.is_open()){
binary_search_file.clear();
binary_search_file.open(data_file_name, std::ios::out);
binary_search_file.close();
binary_search_file.open(data_file_name, std::ios::out | std::ios::in | std::ios::app);
}
try{
if(binary_search_file.fail()){
throw CustomException("Unspecified table data file error");
}
}
catch (CustomException &custom_exception){ // Using custom exception class
std::cout << custom_exception.what() << std::endl;
return;
}
}
Write data to file
void BinarySearchFile::writeT(std::string attribute){
try{
if(binary_search_file){
for(auto start = attribute.begin(); start != attribute.end(); ++start){
binary_search_file.put(' ');
binary_search_file.put(*start);
}
binary_search_file.flush();
/*
attribute.resize(attribute.length() * 2);
const char *write_this = attribute.data();
binary_search_file.write(write_this, attribute.length());
*/
}else if(binary_search_file.fail()){
throw CustomException("Attempt to write attribute error");
}
}
catch(CustomException &custom_exception){ // Using custom exception class
std::cout << custom_exception.what() << std::endl;
return;
}
}
Read data file here:
std::string BinarySearchFile::readT(long file_pointer_location, long size_of_data)
{
try{
if(binary_search_file){
std::string data = "";
binary_search_file.seekp(file_pointer_location);
binary_search_file.seekg(file_pointer_location);
while (size_of_data > 0 ){
binary_search_file.get();
data += binary_search_file.get();
size_of_data -= 2;
}
/*
char data[20];
binary_search_file.seekp(filePointerLocation);
binary_search_file.seekg(filePointerLocation);
binary_search_file.read(data, sizeOfData);
*/
return data;
}else if(binary_search_file.fail()){
throw CustomException("Attempt to read attribute error");
}
}
catch(CustomException &custom_exception){ // Using custom exception class
std::cout << custom_exception.what() << std::endl;
}
}
Code that reads the file and prints the result to the screen:
while(true){
//reinitialize the catalog pointer to the beginning
catalog->setPointerBegin();
//display data
do{
if (boost::iequals((domain = catalog->getAttributeDomain()), "string")){
if(dataFile->binary_search_file_status()){
std::cout << dataFile->read_data(filePointer, 20) << " | ";
if (!writer_.fail())
writer_ << dataFile->read_data(filePointer, 20) << " | ";
}
else{
std::cout << "\n";
if (!writer_.fail())
writer_ << "\n";
return true;
}
// update the file pointer
filePointer += 20;
dataFile->set_file_pointer(filePointer);
}
else{
if(dataFile->binary_search_file_status()){
std::cout << dataFile->read_data(filePointer, 10);
if (!writer_.fail())
writer_ << dataFile->read_data(filePointer, 10);
for(int i = 0; i < 5; i++){
std::cout << " ";
if (!writer_.fail())
writer_ << " ";
}
std::cout << " | ";
if (!writer_.fail()){
writer_ << " | ";
}
}
else{
std::cout << "\n";
if (!writer_.fail()){
writer_ << "\n";
}
return true;
}
// update the file pointer
filePointer += 10;
}
} while(catalog->traverseForward() != nullptr);
std::cout << "\n";
if (!writer_.fail())
writer_ << "\n";
}
}
std::ifstream::get returns std::char_traits<char>::eof on failure, which usually has the int value -1. If you interpret that blindly as a valid character and cast to char, you will get '\xff', which in ISO-8859-15 is ÿ.
You should be checking for eof and/or eofbit when you read characters from the file, and especially after seeking.
Related
I'm trying to use libzip in a program that needs to archive several data chunks in different files. At the moment I have a code similar to the following snippet, edited from in-memory.c example in libzip examples.
The zip file is correctly saved with the files inside, but each file contains garbage.
Any help is appreciated.
bool push_files(zip_t* za) {
for (int i = 0; i < 10; i++) {
// Generate data
std::stringstream ss;
ss << "Test file #" << i;
std::string a = ss.str();
zip_source_t* source = zip_source_buffer(za, a.c_str(), a.size(), 0);
if (source == NULL) {
std::cerr << "error creating source: " << zip_strerror(za) << std::endl;
return false;
}
// Add buffer with filename
std::stringstream fname;
fname << "TEST-" << i;
a = fname.str();
if (zip_file_add(za, a.c_str(), source, ZIP_FL_ENC_UTF_8) < 0) {
std::cerr << "error adding source: " << zip_strerror(za) << std::endl;
return false;
}
}
return true;
}
int main() {
zip_source_t* src;
zip_error_t error;
zip_t* za;
zip_error_init(&error);
if ((src = zip_source_buffer_create(NULL, 0, 1, &error)) == NULL) {
std::cerr << "can't create source: " << zip_error_strerror(&error) << std::endl;
zip_error_fini(&error);
return 1;
}
if ((za = zip_open_from_source(src, ZIP_TRUNCATE, &error)) == NULL) {
std::cerr << "can't open zip from source: " << zip_error_strerror(&error) << std::endl;
zip_source_free(src);
zip_error_fini(&error);
return 1;
}
zip_error_fini(&error);
zip_source_keep(src);
if (!push_files(za))
return -1;
if (zip_close(za) < 0) {
std::cerr << "can't close zip archive" << zip_strerror(za) << std::endl;
return 1;
}
// ... omissis, save archive to file as in in-memory.c
}
zip_source_buffer does not copy the data out of the buffer - it just creates a zip_source_t which points to the same buffer. So you must keep the buffer alive until you're done adding the file.
Your code does not keep the buffer alive. The buffer you use is a.c_str() which is the data buffer of the string a. Fair enough, so far. But then before adding the file, you reassign the variable a = fname.str(); which (probably) frees that buffer and allocates a new one.
Solution: use a separate variable for the filename. Don't overwrite a until the file has been added.
std::fstream pasaka("my_file", std::fstream::in | std::fstream::out);
std::fstream pusuku("my_file1", std::fstream::in | std::fstream::out);
std::string line;
if (pasaka.is_open())
{
//while (std::getline(pasaka, line))
//std::cout << line << std::endl;
// pusuku << line << std::endl;
while (!pasaka.eof())
{
if (pasaka.get() == 'a')
{
pasaka.seekp((pasaka.tellp() - static_cast<std::streampos>(1)));
pasaka.put('u');
pasaka.seekp(pasaka.tellp());
}
else if (pasaka.get() == 'A')
{
pasaka.seekp((pasaka.tellp() - static_cast<std::streampos>(1)));
pasaka.put('U');
pasaka.seekp(pasaka.tellp());
}
}
pusuku.close();
pasaka.close();
}
else {
std::cout << "Faild to open" << '\n';
}
return 0;
the issues:
if the code that is commented (first while loop and everything in it ) the program does 0 switches
2)if A is found it doesn't delete the A characther but just adds U
result received: ( from txt file )
uuuuuuu
UAUAAAA
result expected ( from txt file )
uuuuuuu
UUUUUUU
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.
IN IOS app, module written in C++ I am writing my data (map of basic strings and integers) to a text file. Using following method:
bool Recognizer::saveMap(const char * s)
{
if(trainingData.model && !trainingData.model.empty()) {
const string filename = string(s);
std::ofstream file(s, ios_base::trunc );
try{
if(! file.is_open())
{
file.open(s);
}
for (map<String,int>::iterator it=trainingData.idMap.begin(); it!=trainingData.idMap.end(); ++it)
{
cout << it->second << " " << it->first << endl;
file << it->first << endl << it->second << endl;
}
file.close();
}
catch(cv::Exception & e){
if(file.is_open())
file.close();
int code = e.code;
string message = e.err;
cerr << "cv::Exeption code: " << code << " " << message << endl;
return false;
}
std::streampos fileLength = iosFileSize(s);
cout << "Saved map to: " << filename << " length: " << fileLength << endl;
return true;
}
return false;
}
My contains one entry and console output indicates that two lines: string, string representing number have been written to my file.
Subsequent opening file for reading and reading using getline or using stream operator indicates that file is empty:
bool Recognizer::loadMap(const char * s)
{
std::streampos fileLenght = iosFileSize(s);
std::ifstream file(s, ios::in);
try{
if(file.is_open())
{
string name;
string lineName;
string lineTag;
int tag;
int count = 0;
while(getline(file,name))
{
if(getline(file,lineTag))
{
tag = stoi(lineTag,0,10);
count++;
cout << tag << " " << name << endl;
trainingData.idMap[name]=tag;
trainingData.namesMap[tag]=name;
}
}trainingData.personsCount=count;
file.close();
}
}
catch(cv::Exception & e){
if(file.is_open())
file.close();
int code = e.code;
string message = e.err;
cerr << "cv::Exeption code: " << code << " " << message << endl;
return false;
}
cout << "Loaded map from: " << s << " lenght: "<< fileLenght << endl;
return true;
}
I also copied from one of stackoverflow answers method returning file lenght and using it to verify lenghth of the file after write operation:
std::streampos iosFileSize( const char* filePath ){
std::streampos fsize = 0;
std::ifstream file( filePath, std::ios::binary );
fsize = file.tellg();
file.seekg( 0, std::ios::end );
fsize = file.tellg() - fsize;
file.close();
return fsize;
}
The file path passed to saveMap and loadMap seems to be legit. With path that the app could not write to, attempt to write caused exception.
There are no errors returned by write operation but both, attempts to read and iosFileSize() indicate that file is empty.
I am not sure if i need call file.open() and file.close() or file is open and closed automatically when output stream is created and later goes out of scope.
I experimented with those with the same result ( call to file.is_open returns true so the block calling file.open() is skipped.
What am I doing wrong?
I appreciate all responses.
It does not seem like you call file.flush(); anywhere in Recognizer::saveMap() after writing to the file stream. std::ofstream::flush() saves changes you've made to the file. Add file.flush(); between when you make changes to the code and when you close the file. See if that remedies your issue.
I also had the same issue. Using file.flush() everytime after you insert to a file can save your file.
However if you insert something like this, say,
file << "Insert This"; You will need to add file.flush().
But some people have issues, like if you just insert file << "Insert This" << endl; , this works fine. The key point here is that, std::endl calls flush() everytime it is used internally. you can say it is a shortend form of "\n" + flush().
I believe from looking at your code that you are overwriting your data when you open the file in the second program you should be using something like this.
std::fstream fs;
fs.open ("test.txt", ios::app)
instead of doing the ios::in
I'm trying to write contents of datastructure to a file but for some reason file.is_open() returns false. Am I missing something? Printing should work fine as I tested it with cout.
std::ofstream file;
file.open(filename, std::ofstream::out | std::ofstream::trunc);
for(int i = 0; i < 1000; ++i) {
Candy* tmp = index[i];
for(; tmp; tmp = tmp->next){
if(file.is_open()){
file << tmp->ID << ";" << tmp->amount << ";" << tmp->location <<
}
else{
std::cout << "error" << std::endl;
}
}
file.close();
}
Could it be that your curly braces are mismatched?
You never close out of the scope of the first for loop, so you are closing the file on the first iteration of the loop.
Do you have the correct permissions to write to the file path? Do the does the path to the file actually exist?
You can check the errno to find out what went wrong.
#include <cerrno>
std::cout << "File error: " << strerror( errno ) << std::endl;