C++: Getting incorrect file size - c++

I'm using Linux and C++. I have a binary file with a size of 210732 bytes, but the size reported with seekg/tellg is 210728.
I get the following information from ls-la, i.e., 210732 bytes:
-rw-rw-r-- 1 pjs pjs 210732 Feb 17 10:25 output.osr
And with the following code snippet, I get 210728:
std::ifstream handle;
handle.open("output.osr", std::ios::binary | std::ios::in);
handle.seekg(0, std::ios::end);
std::cout << "file size:" << static_cast<unsigned int>(handle.tellg()) << std::endl;
So my code is off by 4 bytes. I have confirmed that the size of the file is correct with a hex editor. So why am I not getting the correct size?
My answer: I think the problem was caused by having multiple open fstreams to the file. At least that seems to have sorted it out for me. Thanks to everyone who helped.

Why are you opening the file and checking the size? The easiest way is to do it something like this:
#include <sys/types.h>
#include <sys/stat.h>
off_t getFilesize(const char *path){
struct stat fStat;
if (!stat(path, &fStat)) return fStat.st_size;
else perror("file Stat failed");
}
Edit: Thanks PSJ for pointing out a minor typo glitch... :)

At least for me with G++ 4.1 and 4.4 on 64-bit CentOS 5, the code below works as expected, i.e. the length the program prints out is the same as that returned by the stat() call.
#include <iostream>
#include <fstream>
using namespace std;
int main () {
int length;
ifstream is;
is.open ("test.txt", ios::binary | std::ios::in);
// get length of file:
is.seekg (0, ios::end);
length = is.tellg();
is.seekg (0, ios::beg);
cout << "Length: " << length << "\nThe following should be zero: "
<< is.tellg() << "\n";
return 0;
}

When on a flavour of Unix, why do we use that, when we have the stat utlilty
long findSize( const char *filename )
{
struct stat statbuf;
if ( stat( filename, &statbuf ) == 0 )
{
return statbuf.st_size;
}
else
{
return 0;
}
}
if not,
long findSize( const char *filename )
{
long l,m;
ifstream file (filename, ios::in|ios::binary );
l = file.tellg();
file.seekg ( 0, ios::end );
m = file.tellg();
file.close();
return ( m – l );
}

Is it possible that ls -la is actually reporting the number of bytes the file takes up on the disk, instead of its actual size? That would explain why it is slightly higher.

Related

std::ifstream.read() doesn't return anything to my buffer

When I am reading file with function read(), this function doesn't save data to my buffer smoke. I'm trying to read a file and save it to smoke with binary content.
How can I do it better, with vectors?
std::ifstream file("favicon.ico", std::ios::binary);
char ak47xd[1024];
std::string testxcs = "";
if (file.is_open()) {
file.seekg(0, file.end);
const size_t length = file.tellg();
file.seekg(0, file.beg);
char smoke[318];
file.read(smoke, length);
printf("sss: %s\n",smoke);
for (int i = 0; i < length; i++) {
printf("sk: %c\n",smoke[i]);
testxcs += smoke[i];
//printf("%i : %X\n", i, smoke[i] & 0xFF);
//testxcs += (smoke[i] & 0xFF);
//printf("Smoke: %s\n",testxcs.c_str());
}
}
Output:
Here picture
Here problem
You are reinterpret_casting a char** to char*, your program's behaviour is undefined. Probably what is happening is the bytes are being written somewhere else.
You don't need three buffers to read into
#include <iostream>
#include <string>
std::ifstream file("favicon.ico", std::ios::binary);
if (file) {
file.ignore( std::numeric_limits<std::streamsize>::max() );
std::streamsize length = file.gcount();
file.clear(); // Since ignore will have set eof.
file.seekg( 0, std::ios_base::beg );
std::string testxcs(length, 0);
file.read(testxcs.data(), length);
std::cout << "sss: " << testxcs << "\n";
for (char c : testxcs)
{
std::cout << "sk: " << c << "\n";
}
}

Write vector of unsigned char to binary file c++

I am reading binary file cmd.exe into unsigned chars array. Total bytes read into bytes_read are 153. I converted it to base64 string and then decode this string back (code from 2nd answer base64 decode snippet in c++) into vector<'BYTE>. Here BYTE is unsigned char.
decodedData.size() is also 153. But when I write this vector to file in binary mode to get my cmd.exe file again I get only 1 KB file. What thing I missed?
// Reading size of file
FILE * file = fopen("cmd.exe", "r+");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Reading data to array of unsigned chars
file = fopen("cmd.exe", "r+");
unsigned char * myData = (unsigned char *)malloc(size);
int bytes_read = fread(myData, sizeof(unsigned char), size, file);
fclose(file);
std::string encodedData = base64_encode(&myData[0], bytes_read);
std::vector<BYTE> decodedData = base64_decode(encodedData);
////write data to file
ofstream outfile("cmd.exe", ios::out | ios::binary);
outfile.write((const char *)decodedData.data(), decodedData.size());
Update:
Thanks #chux for suggesting "r+" --> "rb+" Problem resolved.
You marked this as C++.
This is one C++ approach using fstream to read a binary file. To simplify for this example, I created a somewhat bigger m_buff than needed. From the comments, it sounds like your fopen("cmd.exe", "r+") was in error, so I'm only providing a C++ binary read.
Method tReader() a) opens a file in binary mode, b) reads the data into m_buff, and c) captures gCount for display.
It also demonstrates one possible use of chrono to measure duration.
#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock HRClk_t;
typedef HRClk_t::time_point Time_t;
typedef std::chrono::microseconds US_t;
using namespace std::chrono_literals; // suffixes 100ms, 2s, 30us
#include <iostream>
#include <fstream>
#include <cassert>
class T516_t
{
enum BuffConstraints : uint32_t {
Meg = (1024 * 1024),
END_BuffConstraints
};
char* m_buff;
int64_t m_gCount;
public:
T516_t()
: m_buff (nullptr)
, m_gCount (0)
{
m_buff = new char[Meg];
}
~T516_t() = default;
int exec()
{
tReader();
return(0);
}
private: // methods
void tReader()
{
std::string pfn = "/home/dmoen/.wine/drive_c/windows/system32/cmd.exe";
// open file in binary mode
std::ifstream sIn (pfn, std::ios_base::binary);
if (!sIn.is_open()) {
std::cerr << "UNREACHABLE: unable to open sIn " << pfn
<< " priviledges? media offline?";
return;
}
Time_t start_us = HRClk_t::now();
do
{
// perform read
sIn.read (m_buff, Meg);
// If the input sequence runs out of characters to extract (i.e., the
// end-of-file is reached) before n characters have been successfully
// read, buff contains all the characters read until that point, and
// both eofbit and failbit flags are set
m_gCount = sIn.gcount();
if(sIn.eof()) { break; } // exit when no more data
if(sIn.failbit ) {
std::cerr << "sIn.faileBit() set" << std::endl;
}
}while(1);
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
sIn.close();
std::cout << "\n " << pfn
<< " " << m_gCount << " bytes"
<< " " << duration_us.count() << " us"
<< std::endl;
} // int64_t tReader()
}; // class T516_t
int main(int , char**)
{
Time_t start_us = HRClk_t::now();
int retVal = -1;
{
T516_t t516;
retVal = t516.exec();
}
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
std::cout << " FINI " << duration_us.count() << " us" << std::endl;
return(retVal);
}
One typical output on my system looks like:
/home/dmoen/.wine/drive_c/windows/system32/cmd.exe 722260 bytes 1180 us
FINI 1417 us
Your results will vary.
Your ofstream use looks good (so did not replicate).

Reading Binary Files w/ ifstream

I'm trying to read in an .exe and write it back out. My code works with .txt files but for some reason it is breaking executables. What am I doing wrong?
I'm not sure if I am reading it wrong or writing it wrong..
#include <string>
#include <vector>
#include <iostream>
#include <filesystem>
#include <unordered_set>
#include <Windows.h>
unsigned char *ReadFileAsBytes(std::string filepath, DWORD &buffer_len)
{
std::ifstream ifs(filepath, std::ofstream::binary | std::ifstream::ate);
if (!ifs.is_open())
{
return(nullptr);
}
// Go To End
ifs.seekg(0, ifs.end);
// Get Position (Size)
buffer_len = static_cast<DWORD>(ifs.tellg());
// Go To Beginning
ifs.seekg(0, ifs.beg);
// Allocate New Char Buffer The Size Of File
PBYTE buffer = new BYTE[buffer_len];
ifs.read(reinterpret_cast<char*>(buffer), buffer_len);
ifs.close();
return buffer;
}
void WriteToFile(std::string argLocation, unsigned char *argContents, int argSize)
{
std::ofstream myfile;
myfile.open(argLocation);
myfile.write((const char *)argContents, argSize);
myfile.close();
}
int main()
{
// Config
static std::string szLocation = "C:\\Users\\Admin\\Desktop\\putty.exe";
static std::string szOutLoc = "C:\\Users\\Admin\\Desktop\\putty2.exe";
DWORD dwLen;
unsigned char *szBytesIn = ReadFileAsBytes(szLocation, dwLen);
std::cout << "Read In " << dwLen << " Bytes" << std::endl;
// Write To File
WriteToFile(szOutLoc, szBytesIn, dwLen);
system("pause");
}
You open input file in binary mode, but in this code
std::ofstream myfile;
myfile.open(argLocation);
you open output file without binary mode. And there is no reason to call open separately:
std::ofstream myfile( argLocation, std::ios::out | std::ios::binary | std::ios::trunc);

Size is always zero when reading DRM EDID file

I tried to read the EDID of my monitor connected to LVDS1. I use ArchLinux and C++/clang. My problem is: the file size always returns 0. I don't know if this is a programming problem or something OS specific, other files return a proper file size. Is it a special file? Is the symlink directory /sys/class/drm/card0-DP-1 the problem?
file: /sys/class/drm/card0-LVDS-1/edid
code:
#include <fstream>
#include <iostream>
using namespace std;
typedef unsigned char BYTE;
long
get_file_size(FILE *f)
{
long pos_cursor, pos_end;
pos_cursor = ftell(f);
fseek(f, 0, 2);
pos_end = ftell(f);
fseek(f, pos_cursor, 0);
return pos_end;
}
int
main()
{
const char *filepath = "/sys/class/drm/card0-LVDS-1/edid";
FILE *file = NULL;
if((file = fopen(filepath, "rb")) == NULL)
{
cout << "file could not be opened" << endl;
return 1;
}
else
cout << "file opened" << endl;
long filesize = get_file_size(file);
cout << "file size: " << filesize << endl;
fclose(file);
return 0;
}
output:
file opened
file size: 0
===
as suggested by MSalters, I tried stat for the file size. Also returns 0. I assume the code is correct, so it is somehow just not possible to access the file?
I also tried the symlink target path (/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-LVDS-1/edid), just in case that was the problem - but still 0.
code:
#include <iostream>
#include <sys/stat.h>
using namespace std;
int
main()
{
const char *filepath = "/sys/class/drm/card0-LVDS-1/edid";
struct stat results;
if (stat(filepath, &results) == 0)
cout << results.st_size << endl;
else
cout << "error" << endl;
return 0;
}
output
0
===
I tried other files in the same directory (dpms edid enabled i2c-6 modes power status subsystem uevent). They all return a filesize of 4096 except edid.
I suspect that fseek(f, 0, 2); might mean fseek(f, 0, SEEK_CUR); which obviously doesn't do anything. You'd want SEEK_END which isn't portable, but then again /sys/ isn't either. (Of course, do #include <stdio.h>)
But considering it's already Linux-specific, why not use stat ?

How to determine size of a huge binary file in c++

To determine a size of a binary file seems to always involve read the whole file into memory. How do I determine the size of a very large binary file which is known way bigger than the memory can take?
On most systems, there's stat() and
fstat() functions (not part of ANSI-C, but part of POSIX). For Linux, look at the man page.
EDIT: For Windows, the documentation is here.
EDIT: For a more portable version, use the Boost library:
#include <iostream>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
if (argc < 2)
{
std::cout << "Usage: tut1 path\n";
return 1;
}
std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
return 0;
}
#include <cstdio>
FILE *fp = std::fopen("filename", "rb");
std::fseek(fp, 0, SEEK_END);
long filesize = std::ftell(fp);
std::fclose(fp);
Or, use ifstream:
#include <fstream>
std::ifstream fstrm("filename", ios_base::in | ios_base::binary);
fstrm.seekg(0, ios_base::end);
long filesize = fstrm.tellg();
This should work:
uintmax_t file_size(std::string path) {
return std::ifstream(path, std::ios::binary|std::ios::ate).tellg();
}