Search code examples
cfileif-statementfopenfwrite

if file doesn't exits create and write in C


I just want to write "null"s if it doesn't exist. And if it exists I will write book names etc. not null. so I tried this code.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 30

int main() {
    FILE * shelfFile;
    //if file doesn't exist
    char start[MAX] = "NULL";
    if (!(shelfFile = fopen("shelf.txt", "r"))) {
        shelfFile = fopen("shelf.txt", "w");
        printf("In if block\n");
        fwrite(start, sizeof(char), MAX, shelfFile);
        fwrite("\n", sizeof(char), 1, shelfFile);
    }   
    fclose(shelfFile);

    system("PAUSE");
    return 0;
}

when I run this code, the file has not been created and printf doesn't work too. Shortly it doesn't enter in if code block. What is wrong with this?


Solution

  • If you want to stick to standard C, Acorn's answer is spot on. As far as I know, testing whether a file exists is relegated to operating system-specific APIs.

    On Windows, you could write the function to test if a file exists by passing the filename to the GetFileAttributesFunction as seen here. Once you have that, all you have to do is write the function to conditionally create the file if it doesn't already exist.

    #include <Windows.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    
    void createFile(const char *filename) {
        const HANDLE newFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
    
        if (newFile == INVALID_HANDLE_VALUE) {
            fprintf(stderr, "[Error]: Failed to open file: %s\n", filename);
    
            exit(EXIT_FAILURE);
        }
    }
    
    int FileExists(const char *filename) {
        const DWORD fileAttributes = GetFileAttributes(filename);
    
        if (fileAttributes == 0xFFFFFFFF)
            return 0;
    
        return 1;
    }
    
    void ConditionallyCreateFile(const char *filename) {
        if (!FileExists(filename))
            createFile(filename);
    }
    
    
    int main()
    {
        const char *filename = "test-file.txt";
        printf("File exists: %d\n", FileExists(filename));
        ConditionallyCreateFile(filename);
        printf("File exists: %d\n", FileExists(filename));
    
        return EXIT_SUCCESS;
    }
    

    When I run the code the first time, this is the output:

    File exists: 0
    File exists: 1
    

    Then the second time:

    File exists: 1
    File exists: 1
    

    Having said that, however, I will point out that if you are using the Win32 API, you are almost certainly using the Microsoft compiler, so you could just write the same code in C++, which I recommend. This is what it would look like then:

    #include <Windows.h>
    
    #include <iostream>
    #include <iomanip>
    #include <string>
    
    namespace FS {
        void CreateFile(const std::string& filename) {
            const auto newFileHandle = ::CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
    
            if (newFileHandle == INVALID_HANDLE_VALUE) {
                std::cerr << "Failed to create new file...\n";
    
                exit(EXIT_FAILURE);
            }
        }
    
        bool FileExists(const std::string& filename) {
            const auto fileAttributes = ::GetFileAttributes(filename.c_str());
    
            if (fileAttributes == 0xFFFFFFFF)
                return false;
    
            return true;
        }
    
        void ConditionallyCreateFile(const std::string& filename) {
            if (!FileExists(filename))
                FS::CreateFile(filename);
        }
    }
    
    int main()
    {
        const std::string filename = "test-file.txt";
    
        std::cout << std::boolalpha << "File exists: " << FS::FileExists(filename) << '\n';
        FS::ConditionallyCreateFile(filename);
        std::cout << "File exists: " << FS::FileExists(filename) << '\n';
    
        return EXIT_SUCCESS;
    }
    

    If I delete the previously created test-file.txt and run the program again, this is the output:

    File exists: false
    File exists: true
    

    And then the second time:

    File exists: true
    File exists: true
    

    To summarize, determining whether a file exists before creating it is an operating system-specific task. I assumed you were on Windows, since statistically speaking it was the most likely scenario, but let me know if you need help writing this on Linux. Good luck