Determine the size of a binary file - c++

I'm trying to read a binary file and I need to determine its size, but regardless of the method I've tried, I'm getting a size of zero.
For example:
fstream cbf(address, ios::binary | ios::in | ios::ate);
fstream::pos_type size = cbf.tellg(); // Returns 0.
char* chunk = new char[size];
cbf.read(chunk, size);
//...
If I were to use the following:
#include <sys/stat.h>
struct stat st;
stat(address.c_str(),&st);
int size = st.st_size;
The size is still zero. I've also tried the following, but it's still zero.
File* fp;
fp = open(address.c_str(), "rb");
How do I get the size of the file?
Thanks for the responses... I've identified the problem:
The binary file I was trying to access was created during the execution, and I just had forgotten to close it before trying to read from it...

Neither of your examples checks for failure. This program, using your first method, works perfectly well for me. It correctly identifies the size of /etc/passwd and the non-existence of /etc/motd.
#include <fstream>
#include <iostream>
#include <string>
void printSize(const std::string& address) {
std::fstream motd(address.c_str(), std::ios::binary|std::ios::in|std::ios::ate);
if(motd) {
std::fstream::pos_type size = motd.tellg();
std::cout << address << " " << size << "\n";
} else {
perror(address.c_str());
}
}
int main () {
printSize("/etc/motd");
printSize("/etc/passwd");
}

Try to load the file in this method.
Note: Use ifstream insted of fstream in this line ifstream cbf(address, ios::binary | ios::in );
long size;
ifstream cbf(address, ios::binary | ios::in);
cbf.seekg(0, ios::end);
size=cbf.tellg();
cbf.seekg(0, ios::beg);
char* chunk = new char[size];
cbf.read(chunk, size);

Related

How to read in binary mode and transfer the information to new file

i tried to open and read an application in binary mode and get 100 characters(For a large file, i did this so that i could read all the characters) in binary mode and then transfer them to new file(in fact, this program will be the same as the previous program, but with a different name ) to find out if it works properly or not
so anyway my source code is:
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main()
{
//Vector of 100 characters initialised to 0
vector<char> ch(100, 0);
ifstream file("example.exe",ios::in|ios::binary);
if (file.is_open())
{
while (file)
{
file.read(ch.data(), 100);
// Get the number of bytes actually read
size_t count = file.gcount();
ch[file.gcount()] = '\0';
//cout << ch.data() << endl;
ofstream output("output.exe", ios::out | ios::binary | ios::app);
output.write(ch.data(), sizeof(100));
output.close();
}
}
file.close();
}
my problem is the output with the correct information is not included and the size is smaller than the original application(example.exe) what is happening?
The line output.write(ch.data(), sizeof(100));
should be replaced with output.write(ch.data(), count);
Since sizeof(100) only returns 4, which is the size in bytes of an integer.
You should also remove the line ch[file.gcount()] = '\0'; since file.gcount() might be out of bound.
I just tested it and this works for me
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main()
{
vector<char> ch(100, 0);
ifstream file("app.exe",ios::in|ios::binary);
if (file.is_open())
{
ofstream output("app_copy.exe", ios::out | ios::binary | ios::trunc);
while (file)
{
file.read(ch.data(), 100);
output.write(ch.data(), file.gcount());
}
output.close();
}
file.close();
}
Notice that ios::app is replaced by ios::trunc, which will delete the content of the file when opening.

fstream Checking if file exists c++

Hi guys I am working on an rpg project and I am creating player files so they can save their progress and such.
I've made a test program so I can show you on a more simple scale of what I am looking for
Code:
#include <iostream>
#include <fstream>
#include <string>
int main(){
std::string PlayerFileName;
std::cout << "Name Your Player File Name: ";
std::cin >> PlayerFileName;
std::ofstream outputFile;
std::string FileName = "Players/" + PlayerFileName;
outputFile.open(FileName); // This creates the file
// ...
}
I want to check and see if the Player File Name already exists the the Players directory so people cant save over their progress.
Thanks!
I suggest opening the file in binary mode and using seekg() and tellg() to count it's size. If the size is bigger than 0 bytes this means that the file has been opened before and has data written in it:
void checkFile()
{
long checkBytes;
myFile.open(fileName, ios::in | ios::out | ios::binary);
if (!myFile)
{
cout << "\n Error opening file.";
exit(1);
}
myFile.seekg(0, ios::end); // put pointer at end of file
checkBytes = myFile.tellg(); // get file size in bytes, store it in variable "checkBytes";
if (checkBytes > 0) // if file size is bigger than 0 bytes
{
cout << "\n File already exists and has data written in it;
myFile.close();
}
else
{
myFile.seekg(0. ios::beg); // put pointer back at beginning
// write your code here
}
}
Check if file exists like this:
inline bool exists (const std::string& filename) {
struct stat buffer;
return (stat (filename.c_str(), &buffer) == 0);
}
Using this needs to remember to #include <sys/stat.h>.
-
In C++14 it is possible to use this:
#include <experimental/filesystem>
bool exist = std::experimental::filesystem::exists(filename);
& in C++17: (reference)
#include <filesystem>
bool exist = std::filesystem::exists(filename);

Reading and writing binary information with C++

I'm having some trouble reading and writing binary information. I can successfully write a simple string to a text file, in this case, my file 'output.dat' contains the sentence "Hello, this is a sentence".
However, I cannot read my information back. I cannot identify the problem. I intend to change every byte of the information read from the binary file later on so returning the value as a string helps.
Thanks for any help you can provide.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void write(const string &input) {
fstream output("output.dat", ios::out | ios::binary);
if (output.is_open()) {
output.write(input.c_str(), input.size());
output.close();
}
}
string read(const string &fname) {
int size;
char* buffer;
fstream input(fname, ios::in | ios::binary);
if (input.is_open()) {
input.seekg(0, ios::end);
size = input.tellg();
input.seekg(0, ios::beg);
buffer = new char[size];
input.read(buffer, size);
input.close();
}
string result(buffer);
return result;
}
int main () {
cout << read("output.dat") << endl;
system("pause");
return 0;
}
The bug is here.
char* buffer;
input.read(buffer, size);
You're reading to the memory that buffer is pointing to.
But where is it pointing to? The pointer buffer has never been initialized.
If you know how much space you need, an approach like this will work.
std::vector<char> buffer(size);
input.read(&buffer.front(), size);
I really cannot understand what is going wrong in this code, as it looks fine, and works fine with me. Nevertheless, the buffer you are allocating is missing the null terminator to mark char-string end. Just change it to this:
buffer = new char[size+1];
input.read(buffer, size);
buffer[size] = 0;

I'm trying to set up a file stream or something like that, but I'm very confused as to what I'm supposed to do

#include <iostream>
#include <fstream>
int main() {
std::ofstream outfile("text.txt", ios::trunc);
std::ifstream infile("text.txt", ios::trunc);
outfile.seekp(0);
std::cout << "This is a file";
infile.seekg(0, ios::end);
int length = infile.tellg();
infile.read(0, length);
infile.close();
outfile.close();
return 0;
}
I think I get the idea behind this, but I feel like (and I'm pretty sure) I have no idea what I'm doing. I've looked it up and everything has confused me. I've read through a C++ reference, and then I googled it, but I still don't understand what I'm doing wrong.
#include <iostream>
#include <fstream>
#include <cstring>
int main() {
std::fstream file("text.txt", std::ios_base::in | std::ios_base::out);
file << "This is a file";
int length = file.tellg();
std::string uberstring;
file >> uberstring;
std::cout << uberstring;
char *buffer = new char[length + 1];
file.read(buffer, length);
buffer[length] = '\0';
file.close();
delete [] buffer;
return 0;
}
I tried this, but it isn't printing anything. Why isn't this working?
If you want to read and write to the same file, just use a normal std::fstream ... there is no need to attempt and open the same file as both a ifstream and ofstream. Also if you want to write data to the file, use the operator<< on the actual fstream instance object, not std::cout ... that will simply write to wherever std::cout is set, which is typically the console. Finally, the call to read has to go back into a buffer, you can't use NULL as an argument. So your code would change to the following:
int main()
{
std::fstream file("text.txt", ios_base::in | ios_base::out);
//outfile.seekp(0); <== not needed since you just opened the file
file << "This is a file"; //<== use the std::fstream instance "file"
//file.seekg(0, ios::end); <== not needed ... you're already at the end
int length = file.tellg();
//you have to read back into a buffer
char* buffer = new char[length + 1];
infile.read(buffer, length);
buffer[length] = '\0'; //<== NULL terminate the string
file.close();
delete [] buffer;
return 0;
}

Write to the middle of an existing binary file c++

I'm trying to open a binary file for writing without erasing the content. But I do not want to write to eof. I want to write to a specific position in file.
Here is a litte example:
ofstream out("test.txt", ios::binary | ios::app);
for(int i = 0; i < 100; i++)
out.put('_');
out.write("Hallo", 5);
out.close();
ofstream out2("test.txt", ios::binary | ios::app);
out2.seekp(10);
out2.write("Welt", 4);
out2.close();
If using app, seek doesn't work. If not using app opening file erases data. Does anybody know an answer?
try the second overload of seekp, which allows you to provide an offset and a direction, this could be begining of file in your case (i.e. ios_base::beg). This of course assumes you know what you are doing and all you want to do is overwrite an existing number of characters.
EDIT: here is fully working example:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
{
ofstream out("test.txt", ios::binary);
for(int i = 0; i < 100; i++)
out.put('_');
out.write("Hallo", 5);
}
{
fstream out2("test.txt", ios::binary | ios::out | ios::in);
out2.seekp(10, ios::beg);
out2.write("Welt", 4);
}
}
When opening with ios::app, it is as if you open a new file that just happened to be attached to an existing file: you can not access the existing file. I'm not sure, because I would do as in Kerrek's answer, but if you really want to try, you probably have to open with "ios::in | ios::out", similar to fopen("test.txt", "rw").
Or as crashmstr points out: ios::out might be enough.
You cannot magically extend the file from the middle. Perhaps easiest to write to a new file: First copy the initial segment, then write your new data, then copy the remaining segment. When all is done, you can overwrite the original file.
According to the specification of fstream here
fstream::open
the ios::app "Sets the stream's position indicator to the end of the stream before EACH output operation." So ios::app doesn't work for replacing, seeks of any sort fail, at least for me.
Just using ios::out does wipe out the file contents preserving only the size, basically turning the file into trash.
ios::in|ios::out turned out as the only working thing for me.
Working Code: This code searches for a string (OLD-STRING) in cout.exe and replaces with a new string (NEW-STRING).
`#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
fstream ifs;
ifs.open ("C:\\Users\\user\\Desktop\\cout.exe", fstream::binary | fstream::in | fstream::out);
std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
size_t pos = str.find("OLD-STRING");
if (pos != string::npos)
{
cout << "string found at position: " << int(pos) << endl;
ifs.seekp(pos);
ifs.write("NEW-STRING", 10);
}
else
{
cout << "could not find string" << endl;
}
if (ifs.is_open())
ifs.close();
return 0;
}`