Home > OS >  fwrite() writes garbage at the end
fwrite() writes garbage at the end

Time:08-26

I'm trying to write a function that execute a sql file with postgres. Postgres rise me an exception but without specificate the error. So I tryed to rewrite what it read, and I discovery that the file has some garbage at end

    stat("treebase.sql",&buf);
    dbschema= new (std::nothrow) char[buf.st_size 1];
    if(!dbschema)
    {
        wxMessageBox(_("Not Enough memory"));
        return;
    }
    if( !(fl=fopen("treebase.sql","r")))
    {
        wxMessageBox(_("Can not open treebase.sql"));
        delete []dbschema;        
        return;
    };
    fo=fopen("tbout.sql","w");
    fread(dbschema,sizeof(char),buf.st_size,fl);
    fclose(fl);
    dbschema[buf.st_size]='\0';
    fwrite(dbschema,sizeof(char),buf.st_size 1,fo);
    fflush(fo);
    fclose(fo);

and the result is

![screen shot][1] The input file 150473 length, the output is 156010. I really can not undersand where the 5000 bytes come from. where is the bug? [1]: https://i.stack.imgur.com/IXesz.png

CodePudding user response:

You probably can't read buf.st_size much of data, because of the mode of fopen is "r" which defaults to text modes. In text mode fread and fwrite may do some conversions on what you read or write to match the environment special rules about text files such as end of lines. Use "rb" and "wb" modes for fopen for reading and writing binary files as is respectively.

Also, I would rather use fseek and ftell to get the size of file instead of stat.

CodePudding user response:

Here's an example of how you could read the content of the file into memory and then write down an exact copy to another file. I added error checking too to make it clear if anything goes wrong. There's also no need to use stat etc. Plain standard C will do.

#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <stdexcept>
#include <string>

std::string get_file_as_string(const std::string& filename) {
    std::ifstream fl(filename, std::ios::binary); // binary mode

    if(!fl) throw std::runtime_error(std::strerror(errno));

    // return the content of the whole file as a std::string
    return {std::istreambuf_iterator<char>(fl),
            std::istreambuf_iterator<char>{}};
}

bool write_string_to_file(const std::string& str, const std::string& filename) {
    std::ofstream fo(filename, std::ios::binary);
    if(!fo) return false;

    // return true or false depending on if it succeeded writing the file:
    return static_cast<bool>(fo << str);
}

int main() {
    auto dbschema = get_file_as_string("treebase.sql");

    // use dbschema.c_str() if you need a `const char*`:
    postgres_c_function(dbschema.c_str());

    // use dbschema.data() if you need a `char*`:
    postgres_c_function(dbschema.data());

    if(write_string_to_file(dbschema, "tbout.sql")) {
        std::cout << "success\n";
    } else {
        std::cout << "failure: " << std::strerror(errno) << '\n';
    }
}
  •  Tags:  
  • c
  • Related