51

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)
Crystal
  • 28,460
  • 62
  • 219
  • 393
  • It's too bad that you can't easily get a file descriptor from an `fstream`. You can easily enough check for an empty file using `fstat`, on Unix. :-P – C. K. Young Mar 06 '10 at 01:43

11 Answers11

90

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
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • wouldn't be too hard to add `return pFile.tellg() > 0 || …` – Potatoswatter Mar 06 '10 at 07:59
  • wouldn't `pFile.peek() == '\n'` work just as well? – Viktor Stefanov Aug 09 '21 at 11:46
  • 2
    @ViktorStefanov No, what if the file starts with an empty line? – Marc Aug 25 '21 at 06:49
  • To be fair, in the case of a file, this only works if the stream has just been created (the file has just been opened). If some characters have already been read and the "cursor" has moved to the end of the file, it might say the `file` is empty but in fact it wasn't. You would probably need an additional check `pFile.tellg() != 0 &&` as I think @Potatoswatter was trying to suggest. – Antonio Jan 26 '23 at 10:24
9

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...  
}
pajton
  • 15,828
  • 8
  • 54
  • 65
  • so what exactly is this doing ? it works but I want to know why. is it checking the end of the stream and seeing if its equal to 0? –  Feb 16 '21 at 06:07
  • @user12455086 [`seekg(0, ios::end)`](https://en.cppreference.com/w/cpp/io/basic_istream/seekg) moves the read pointer to the [`end`](https://en.cppreference.com/w/cpp/io/ios_base/seekdir) of the file, then `if inFile.tellg()` tells us that it is still at location zero, then we know the end of the file corresponds with the beginning of the file, hence the file is empty. – Antonio Jan 26 '23 at 10:12
  • The problem with this solution is that it messes up with the stream, Aylian Craspa below shows how to circumvent the problem https://stackoverflow.com/a/69755880/2436175 – Antonio Jan 26 '23 at 10:19
5

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.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
2

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.

Mansoor
  • 2,357
  • 1
  • 17
  • 27
1

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
}
Aylian Craspa
  • 422
  • 5
  • 11
  • Although there are better answers, at least this shows how to reset the stream to a workable state. – Antonio Jan 26 '23 at 10:21
1

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
}
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • For some reason it says file is not empty while it is. – metablaster Jan 25 '23 at 01:00
  • @metablaster Can you provide some context? Did you check the file does not contain any white space? – Antonio Jan 25 '23 at 01:31
  • Yes, I double checked, there is only one line and it is without any spaces, even some Windows API functions return file size to be 4 bytes when the file is blank. I clicked `backspace` a few times to make sure there is absolutely nothing. – metablaster Jan 25 '23 at 01:46
  • @metablaster Sorry to be redundant, can you do a last check with HxD? https://mh-nexus.de/en/hxd/ – Antonio Jan 25 '23 at 02:40
  • I'm using another [hex editor](https://github.com/WerWolv/ImHex), here is screenshot which shows there is one byte `0x00` https://i.imgur.com/aSnSRsB.png – metablaster Jan 25 '23 at 03:57
  • Then the file is effectively not empty...? – Antonio Jan 25 '23 at 16:40
  • `0x00` is ASCII null character, problem is also that `UTF` encoded files may have `BOM` in it, which is therefore 2-4 bytes, but neither `BOM` nor null make any file contents, file is to the user blank, and how to determine if it's blank or not is then issue. there may be any other non printables in it as well. btw. I repoted one issue you might want to track it: https://github.com/WerWolv/ImHex/issues/904 – metablaster Jan 25 '23 at 20:59
  • 1
    @metablaster The important conclusion here is that `filesystem::is_empty` does work. To circumvent the bug of the other app you can have a second check on `filesystem::file_size`, and if size is less than X characters you can open the file and check if the content is all null. – Antonio Jan 26 '23 at 10:04
0
char ch;
FILE *f = fopen("file.txt", "r");

if(fscanf(f,"%c",&ch)==EOF)
{
    printf("File is Empty");
}
fclose(f);
0

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;
}
CroCo
  • 5,531
  • 9
  • 56
  • 88
  • 1
    Fair enough. It's slightly better (due to being _actual_ C++, not C) than user4471014's, though still entirely wasteful and suboptimal. – Lightness Races in Orbit Jan 19 '15 at 17:52
  • @LightnessRacesinOrbit, you are right, however no need for going through all lines of a file. The while loop could be stopped once the first line is being detected and set `isEmpty` to `false`. If that could enhance the code. – CroCo Jan 19 '15 at 17:59
  • I can understand this code is suboptimal but why it is wasteful? The OP is not asking or looking for sufficient or so optimized code. – CroCo Jan 19 '15 at 18:08
  • (a) It's wasteful because you're extracting data that you are never going to use. Reading those characters was pointless. (b) Just because the OP didn't go out of their way to ask for "optimized" code doesn't mean we should go out of our way to provide the opposite. :) – Lightness Races in Orbit Jan 20 '15 at 13:48
0

use this: data.peek() != '\0'

I've been searching for an hour until finaly this helped!

Vytaute
  • 9
  • 1
-1
pFile = fopen("file", "r");
fseek (pFile, 0, SEEK_END);
size=ftell (pFile);
if (size) {
  fseek(pFile, 0, SEEK_SET);
  do something...
}

fclose(pFile)
sizzzzlerz
  • 4,277
  • 3
  • 27
  • 35
-1
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;
}
amna
  • 1