Checking for an empty file in C++ - c++

Is there an easy way to check if a file is empty. Like if you are passing a file to a function and you realize it's empty, then you close it right away? Thanks.
Edit, I tried using the fseek method, but I get an error saying 'cannot convert ifstream to FILE *'.
My function's parameter is
myFunction(ifstream &inFile)

Perhaps something akin to:
bool is_empty(std::ifstream& pFile)
{
return pFile.peek() == std::ifstream::traits_type::eof();
}
Short and sweet.
With concerns to your error, the other answers use C-style file access, where you get a FILE* with specific functions.
Contrarily, you and I are working with C++ streams, and as such cannot use those functions. The above code works in a simple manner: peek() will peek at the stream and return, without removing, the next character. If it reaches the end of file, it returns eof(). Ergo, we just peek() at the stream and see if it's eof(), since an empty file has nothing to peek at.
Note, this also returns true if the file never opened in the first place, which should work in your case. If you don't want that:
std::ifstream file("filename");
if (!file)
{
// file is not open
}
if (is_empty(file))
{
// file is empty
}
// file is open and not empty

Ok, so this piece of code should work for you. I changed the names to match your parameter.
inFile.seekg(0, ios::end);
if (inFile.tellg() == 0) {
// ...do something with empty file...
}

Seek to the end of the file and check the position:
fseek(fileDescriptor, 0, SEEK_END);
if (ftell(fileDescriptor) == 0) {
// file is empty...
} else {
// file is not empty, go back to the beginning:
fseek(fileDescriptor, 0, SEEK_SET);
}
If you don't have the file open already, just use the fstat function and check the file size directly.

C++17 solution:
#include <filesystem>
const auto filepath = <path to file> (as a std::string or std::filesystem::path)
auto isEmpty = (std::filesystem::file_size(filepath) == 0);
Assumes you have the filepath location stored, I don't think you can extract a filepath from an std::ifstream object.

when the file is empty the tellg will give you value 0 if its empty so focus on that and it is the simplest way to find an empty file, if you just create the file it will give you -1.
outfile.seekg(0,ios::end);
if(file.tellg()<1){
//empty
}else{
file.clear(); // clear all flags(eof)
file.seekg(0,ios::beg);//reset to front
//not empty
}

If your use case offer the possibility to check for emptiness before opening the file,C++17 provides you is_empty
#include <filesystem>
if (!std::filesystem::is_empty("path.txt")) {
///Open and use the file
}

char ch;
FILE *f = fopen("file.txt", "r");
if(fscanf(f,"%c",&ch)==EOF)
{
printf("File is Empty");
}
fclose(f);

How about (not elegant way though )
int main( int argc, char* argv[] )
{
std::ifstream file;
file.open("example.txt");
bool isEmpty(true);
std::string line;
while( file >> line )
isEmpty = false;
std::cout << isEmpty << std::endl;
}

use this:
data.peek() != '\0'
I've been searching for an hour until finaly this helped!

pFile = fopen("file", "r");
fseek (pFile, 0, SEEK_END);
size=ftell (pFile);
if (size) {
fseek(pFile, 0, SEEK_SET);
do something...
}
fclose(pFile)

if (nfile.eof()) // Prompt data from the Priming read:
nfile >> CODE >> QTY >> PRICE;
else
{
/*used to check that the file is not empty*/
ofile << "empty file!!" << endl;
return 1;
}

Related

How to detect if a file empty or not in c++? [duplicate]

Is there an easy way to check if a file is empty. Like if you are passing a file to a function and you realize it's empty, then you close it right away? Thanks.
Edit, I tried using the fseek method, but I get an error saying 'cannot convert ifstream to FILE *'.
My function's parameter is
myFunction(ifstream &inFile)
Perhaps something akin to:
bool is_empty(std::ifstream& pFile)
{
return pFile.peek() == std::ifstream::traits_type::eof();
}
Short and sweet.
With concerns to your error, the other answers use C-style file access, where you get a FILE* with specific functions.
Contrarily, you and I are working with C++ streams, and as such cannot use those functions. The above code works in a simple manner: peek() will peek at the stream and return, without removing, the next character. If it reaches the end of file, it returns eof(). Ergo, we just peek() at the stream and see if it's eof(), since an empty file has nothing to peek at.
Note, this also returns true if the file never opened in the first place, which should work in your case. If you don't want that:
std::ifstream file("filename");
if (!file)
{
// file is not open
}
if (is_empty(file))
{
// file is empty
}
// file is open and not empty
Ok, so this piece of code should work for you. I changed the names to match your parameter.
inFile.seekg(0, ios::end);
if (inFile.tellg() == 0) {
// ...do something with empty file...
}
Seek to the end of the file and check the position:
fseek(fileDescriptor, 0, SEEK_END);
if (ftell(fileDescriptor) == 0) {
// file is empty...
} else {
// file is not empty, go back to the beginning:
fseek(fileDescriptor, 0, SEEK_SET);
}
If you don't have the file open already, just use the fstat function and check the file size directly.
C++17 solution:
#include <filesystem>
const auto filepath = <path to file> (as a std::string or std::filesystem::path)
auto isEmpty = (std::filesystem::file_size(filepath) == 0);
Assumes you have the filepath location stored, I don't think you can extract a filepath from an std::ifstream object.
when the file is empty the tellg will give you value 0 if its empty so focus on that and it is the simplest way to find an empty file, if you just create the file it will give you -1.
outfile.seekg(0,ios::end);
if(file.tellg()<1){
//empty
}else{
file.clear(); // clear all flags(eof)
file.seekg(0,ios::beg);//reset to front
//not empty
}
If your use case offer the possibility to check for emptiness before opening the file,C++17 provides you is_empty
#include <filesystem>
if (!std::filesystem::is_empty("path.txt")) {
///Open and use the file
}
char ch;
FILE *f = fopen("file.txt", "r");
if(fscanf(f,"%c",&ch)==EOF)
{
printf("File is Empty");
}
fclose(f);
How about (not elegant way though )
int main( int argc, char* argv[] )
{
std::ifstream file;
file.open("example.txt");
bool isEmpty(true);
std::string line;
while( file >> line )
isEmpty = false;
std::cout << isEmpty << std::endl;
}
use this:
data.peek() != '\0'
I've been searching for an hour until finaly this helped!
pFile = fopen("file", "r");
fseek (pFile, 0, SEEK_END);
size=ftell (pFile);
if (size) {
fseek(pFile, 0, SEEK_SET);
do something...
}
fclose(pFile)
if (nfile.eof()) // Prompt data from the Priming read:
nfile >> CODE >> QTY >> PRICE;
else
{
/*used to check that the file is not empty*/
ofile << "empty file!!" << endl;
return 1;
}

Strange behavior of Mingw Debug

I have problem running and debugging this piece of code:
bool readSectionHeaders(char* path, int numOfSections, int peSectionsOff, IMAGE_SECTION_HEADER* out) {
bool retr = false; //return value
//open file
FILE* file;
file = fopen (path, "rb");
if(file == NULL) {
perror("WRG"); //TODO
return false;
}
do { //do while(false) only for easier error correction
//seek to first section
fseek(file, peSectionsOff, SEEK_SET);
//read all sections
unsigned int count;
IMAGE_SECTION_HEADER sectionHeaders[numOfSections];
count = fread(sectionHeaders, sizeof(IMAGE_SECTION_HEADER), numOfSections, file);
//check Bytes count
if(count != sizeof(IMAGE_SECTION_HEADER)*numOfSections) {
break;
}
//copy sections
memcpy(out, sectionHeaders, count);
//exit successfully
retr = true;
} while(false);
//exit
fclose(file);
return retr;
}
What is strange is that it returns false even when it reads the file. I tried to debug it and here is the strangest part.
I go line by line until this one
if(file == NULL) {
Then even though file is not NULL it skips perror and moves to
return false;
But does not return at all.
I again go line by line until
retr = true;
where it seems to do something, however retr remains false.
Then it closes file and returns with false.
I have never come across something like this.
I tried cleaning project, rebuilding, even deleting files and redownloading them from subversion. Before using this function, I use similar one - I read PE headers. So I though a problem could be with reading the file but it doesn§t explain debug behavior.
After returning from function, I use perror and it writes No error.
I use mingw with QtCreator.
Thanks in advance.
I would do something more like this, if it is able to load the whole array then it will return true.
std::ofstream file(path, std::ios::binary);
if(!file) {
std::cerr << "failed to load file" << std::endl;
return false;
}
file.seekg (peSectionsOff, ios::beg);
IMAGE_SECTION_HEADER sectionHeaders[numOfSections];
size_t size=sizeof(sectionHeaders)*numOfSections;
return //return true if the whole buffer is filled
file.readsome(static_cast<char*>(sectionHeaders), size) == size;
UNTESTED
this might be helpful
http://en.cppreference.com/w/cpp/io
Ok, this was both my and mingw's problem. I've re-installed whole QtSDK with no effect. Then I installed different version of mingw and set qt creator up to use it. Now debugger works without problem. I'm not sure what happened but cerr << "TEST"; also stopped working with the old mingw and this is 100% correct.
As 111111 suggested, problem was with if break clause. I thought read returns number of bytes read and this was simply not true :).
Now it is working, thanks to 111111 for his suggestion :).

need help converting c to c++ (simple error but cant fix)

I have a c++ homework. The homework is asking to convert a c program to c++.
Below is the question:
You are requested to convert the following C function into a C++
function and then embed it into a complete program and test it. Note
that this function copies a binary file of integers and not a text
file. The program must accept the arguments (the file to copy and the
file to be copied to) from the command line.
/* ==================== cpyFile =====================
This function copies the contents of a binary file
of integers to a second file.
Pre fp1 is file pointer to open read file
fp2 is file pointer to open write file
Post file copied
Return 1 is successful or zero if error
*/
int cpyFile (FILE *fp1, FILE *fp2)
{
/* Local Definitions */
int data;
/* Statements */
fseek (fp1, 0, SEEK_END);
if (!ftell (fp1))
{
printf ("\n\acpyFile Error : file empty\n\n");
return 0;
} /* if open error */
if (fseek (fp1, 0, SEEK_SET))
return 0;
if (fseek (fp2, 0, SEEK_SET))
return 0;
while (fread (&data, sizeof (int), 1, fp1))
fwrite (&data, sizeof (int), 1, fp2);
return 1;
} /* cpyFile */
I did my best and managed to convert it, but unfortunately when I'm using it , the file that I get after the copy is empty. Below is my answer:
#include <fstream>
#include <cstdlib>
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
if(argc!=3)
{cerr<<"invalid number of arguments. must be 3."<<endl;exit(1);}
fstream fp1(argv[1],ios::in);
if(!fp1)+{cerr<<argv[1]<<" could not be opened"<<endl;exit(1);}
fstream fp2(argv[2],ios::out);
if(!fp2)+{cerr<<"file could not be found."<<endl;exit(1);}
int data;
fp1.seekg (0,ios::end);
if (!fp1.tellg ())
{
cout<<"\n\acpyFile Error : file empty\n\n";
return 0;
} /* if open error */
if (fp1.seekg (0, ios::beg))
return 0;
if (fp2.seekg (0, ios::beg))
return 0;
while (fp1.read (reinterpret_cast<char*>(&data), sizeof (int)))
{
fp2.seekp(0);
fp2.write (reinterpret_cast<char*>(&data), sizeof (int));
}
return 1;
}
I did my best and everything is working fine, except that when I copy a binary file, the file that i get is empty and I have no idea why.
You need to open the file in binary mode, as others have said, by doing
fstream fp1(argv[1], ios::in | ios::binary); // combine ios::in with ios::binary
fstream fp2(argv[2], ios::out | ios::binary); // combine ios::out with ios::binary
Or you can make them ifstream (in file stream for reading only) and ofstream (out file stream, for writing only) and remove the ios::in and ios::out because ifstream implies ios::in and ofstream implies ios::out:
ifstream fp1(argv[1], ios::binary);
ofstream fp2(argv[2], ios::binary);
You need to do this because if you don't, the file will be translated when you read from or write to it for things like turning line endings from \r\n or \r to just \n, etc, which will mess up your binary data which may happen to have those bytes in them.
This:
if (fp1.seekg (0, ios::beg))
return 0;
if (fp2.seekg (0, ios::beg))
return 0;
Will always make your code return because seekg returns the object you call it on. It's not the equivalent of fseek in this regard because fseek returns 0 on success. So you never get to the while loop. Take those out of the if statements so that it looks like this:
fp1.seekg(0, ios::beg);
fp2.seekg(0, ios::beg);
Or if you have to have the checking, you want to do
if (!fp1.seekg (0, ios::beg)) // notice the added !
return 0;
if (!fp2.seekg (0, ios::beg)) // notice the added !
return 0;
Also, this (inside the while):
fp2.seekp(0);
Is setting the point you are going to write to to the beginning of the file. So you'll never write anything but at the beginning of the file. Just remove that line completely.
Also, you have a return inside the loop which makes it return on the first iteration. Move the return 1; outside the loop so you only return after the loop is finished. Nevermind that, misread due to the unusual brace style.
Every time you read a new data block from fp1, you rewind fp2 to the beginning of the stream, essentially discarding what you have already written to fp2. Try moving fp2.seekp(0) out of your main loop.
You have a few problems. I'd start by fixing this bit:
if (fp1.seekg (0, ios::beg))
return 0;
if (fp2.seekg (0, ios::beg))
return 0;
The seekg method returns a reference to the istream it's called on, so the above is equivalent to this:
fp1.seekg (0, ios::beg);
if (fp1) // i.e., if fp1 is in a valid state (as opposed to e.g. end-of-file)
return 0;
fp2.seekg (0, ios::beg);
if (fp2) // i.e., if fp2 is in a valid state (as opposed to e.g. end-of-file)
return 0;
which is obviously not what you want.
To debug your code, you can use statements like std::cout << "Got to line " << __LINE__ << std::endl; to figure out which parts of the program are actually being run. That would have found the above problem pretty quickly.
Binary files need to be opened specifically in binary mode, so where you have fstream fp1(argv[1],ios::in); you should also add an ios::binary to it like so: fstream fp1(argv[1], ios::in | ios::binary);
In the C++ code you are seeking to the beginning of the output file before writing each number, and therefore the output file will be at most 2 bytes long.

Problem with ifstream

Look at this small code, it open a ifstream :
std::ifstream _fcs;
bool openFile(char* path)
{
istream::pos_type pos;
int tmp = 0;
_fcs.open(path, fstream::binary | fstream::in);
if(!_fcs.is_open())
return false;
tmp = 0;
pos = 0x404;
_fcs.seekg(0x404);
pos = _fcs.tellg(); /// return zero
_fcs >> tmp; ///
_fcs.read((char*)&tmp, 4);
return true;
}
i have two problems.
after seekg, tellg return zero and when I read data it reads from beginning of file.
operator >> seems doesn't work. always return zero!
////------------------------------------------------
thanks for your attentions. I found a crazy solution, but I get confused!
if I call seekg two times, it works, see this code:
bool openFile(char* path)
{
istream::pos_type pos;
int tmp;
bool fail;
_fcs.open(path, fstream::binary | fstream::in);
if(!_fcs.is_open())
return false;
_fcs.seekg(0x402);
_fcs.seekg(0x402); /// When it comments, the tellg returns 0. am i crazy!?
fail = _fcs.fail();
assert(!fail);
pos = _fcs.tellg(); /// return 0x402!!!
/// _fcs >> tmp;
_fcs.read((char*)&tmp, 4);
return true;
}
really, what's happened?
////------------------------------------------------
please help me...
thanks in advanced.
Check the failbit using _fcs.fail() after your seekg call to make sure you haven't specified an invalid file position.
To double check the size use
_fcs.seekg(0,ios::end);
int length = _fcs.tellg();
You also need to use .read() to get the len value, as your file is binary
In binary mode, >> is not supposed to work, you have to use ostream::write.
Does your file actually exists and have a size ? if note, you can't "move" to an arbitrary point in an empty file.

close file with fclose() but file still in use

I've got a problem with deleting/overwriting a file using my program which is also being used(read) by my program. The problem seems to be that because of the fact my program is reading data from the file (output.txt) it puts the file in a 'in use' state which makes it impossible to delete or overwrite the file.
I don't understand why the file stays 'in use' because I close the file after use with fclose();
this is my code:
bool bBool = true
while(bBool){
//Run myprogram.exe tot generate (a new) output.txt
//Create file pointer and open file
FILE* pInputFile = NULL;
pInputFile = fopen("output.txt", "r");
//
//then I do some reading using fscanf()
//
//And when I'm done reading I close the file using fclose()
fclose(pInputFile);
//The next step is deleting the output.txt
if( remove( "output.txt" ) == -1 ){
//ERROR
}else{
//Succesfull
}
}
I use fclose() to close the file but the file remains in use by my program until my program is totally shut down.
What is the solution to free the file so it can be deleted/overwrited?
In reality my code isn't a loop without an end ; )
Thanks in advance!
Marco
Update
Like ask a part of my code which also generates the file 'in use'. This is not a loop and this function is being called from the main();
Here is a piece of code:
int iShapeNr = 0;
void firstRun()
{
//Run program that generates output.txt
runProgram();
//Open Shape data file
FILE* pInputFile = NULL;
int iNumber = 0;
pInputFile = fopen("output.txt", "r");
//Put all orientations of al detected shapes in an array
int iShapeNr = 0;
int iRotationBuffer[1024];//1024 is maximum detectable shapes, can be changed in RoboRealm
int iXMinBuffer[1024];
int iXMaxBuffer[1024];
int iYMinBuffer[1024];
int iYMaxBuffer[1024];
while(feof(pInputFile) == 0){
for(int i=0;i<9;i++){
fscanf(pInputFile, "%d", &iNumber);
fscanf(pInputFile, ",");
if(i == 1) {
iRotationBuffer[iShapeNr] = iNumber;
}
if(i == 3){//xmin
iXMinBuffer[iShapeNr] = iNumber;
}
if(i == 4){//xmax
iXMaxBuffer[iShapeNr] = iNumber;
}
if(i == 5){//ymin
iYMinBuffer[iShapeNr] = iNumber;
}
if(i == 6){//ymax
iYMaxBuffer[iShapeNr] = iNumber;
}
}
iShapeNr++;
}
fflush(pInputFile);
fclose(pInputFile);
}
The while loop parses the file. The output.txt contains sets of 9 variables, the number of sets is unknown but always in sets of 9.
output.txt could contain for example: 0,1,2,3,4,5,6,7,8,8,7,6,5,4,1,2,3,0
update 2
code:
void runProgram(){
//Check if output.txt exists, if so delete it
if(fileExists("output.txt") == 1){
//Delete output.txt
if( remove( "output2.txt" ) == -1 ){
//errormessage
}else{
//succesfull
}
}
//start program
ShellExecute( NULL, TEXT("open"), TEXT("program.exe"), NULL, NULL, SW_SHOWMAXIMIZED);
while(fileExists("output.txt") == 0);
//Close program
int iCheck = system("taskkill /IM program.exe");
if(iCheck != 0){
//error could not shut down
}
}
sorry for using pre again but I don't get the formatting of this site :(
Will it be due to maximum disk space has been reached and there's still data in the file
streams buffer; fclose'ing a file stream flushes it (writes all the data in the buffer), the write operation will fail since maximum disk space is reached.
I suggest you to scope down the problem, by calling fclose() directly after fopen().
If it success, then something is wrong in the code between fclose() and fopen().
There is probably other places in your code where you don't call fclose, leaking the file. Even in this code, if an error occurs between fopen and fclose (or a return statement, or a continue statement, etc...) you'll leak the file. Please, switch to RAII idiom.
Edit: include this into your code:
struct PoorMansFile {
FILE *_file;
PoorMansFile(const char* str1, const char* str2) : _file(fopen(str1,str2)) {}
~PoorMansFile() { if(_file) fclose(_file); }
operator FILE*() const { return _file; }
};
int fclose(PoorMansFile& file)
{
if(!file)
return 0;
int t = fclose(file._file);
file._file = 0;
return t;
}
and replace each
FILE* file = NULL;
file = fopen(str1, str2);
with:
PoorMansFile file(str1, str2);
Tell us if it helps;
The file could still be in use by the CRT or OS - for example, the OS may buffer writes to the disk. fflush() will only flush CRT buffers, not OS buffers.
Just a shot in the dark here...
What is inside runProgram()? Does that function wait until the program has finished before returning? I wonder if the program that is writing the data is, in fact, still running... it's difficult to tell from here, but thought I'd throw it out there!
After reading all answers and comments I could not think of any reason of OP's problem.
Is this multi threaded or reentrant routine?
What will happen if fopen twice and fclose twice on the same file? Is this could be the cause of the problem?
In this thought I suggest two more checks.
printf all fopen/fclose call
after fclose reset file variable to NULL
f = fopen("", ""); printf("fopen => %p", f);
fclose(f); printf("fclose => %p", f); f = 0;
If you are inconvenient with printf debugging you can use OutputDebugString.
extern void __stdcall OutputDebugStringA(const char*) (MS VC only)