1

I am very new to File Handling in C. I would like to ask if there is any way that I could detect if there is an existing data on a file. Because if there's none, I will use "wb", but if there is a data already, I will just use append "ab".

I tried using "wb" instead of "ab" when I write data, but the first data I wrote won't read.

Here is an example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct clientInfo{
    char Name[30];
};

void inputAccounts();
void viewAllRecords();

int main()
{
    showOptions();
}

void inputData()
{
    FILE *fp;

    fp = fopen("hello", "ab");

    struct clientInfo PERSONAL;

    if(fp == NULL)
    {
        printf("Error!!!");
        getch();
    }
    else
    {
        fflush(stdin);
        printf("Enter Name: ");
        gets(PERSONAL.Name);

        fwrite((char *)&PERSONAL, sizeof(struct clientInfo), 1, fp);

        printf("File Created!!!");
        getch();
        fclose(fp);
    }
}

void showOptions()
{
    char choice;
    system("cls");
    printf("\n[1] Add Accounts");
    printf("\n[2] View Records");
    choice = getch();
    if (choice == '1')
    {
        inputData();
    }
    else if (choice == '2')
    {
        viewAllRecords();
    }
    showOptions();
}

void viewAllRecords()
{
    FILE *fp;
    fp = fopen("hello", "rb");

    struct clientInfo PERSONAL;

    fread((char *)&PERSONAL, sizeof(struct clientInfo), 1, fp);

    system("cls");
    if(fp == NULL){
        printf("Error!!!");
        getch();
    }
    else
    {
        while((fread((char *)&PERSONAL, sizeof(struct clientInfo), 1, fp))==1)
        {
            printf("Name: %s\n", PERSONAL.Name);
        }
    }
    getchar();
}
Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
ktl159
  • 51
  • 1
  • 9
  • What is your real problem here. What is your code that fails? If you give poor details, we can only provide generic solutions. If you can read everything except the first set of data, than it is probably an error in your code that you don't show to us. – Gerhardh Jan 31 '19 at 06:54
  • Did you verify your file contents after writing? How can you be sure your problem is with writing to the file instead of reading? – Gerhardh Jan 31 '19 at 06:55
  • I have added a sample of my program. – ktl159 Jan 31 '19 at 07:29
  • Calling `showOptions` recursively will eat Up your stack. – Gerhardh Jan 31 '19 at 07:32
  • For your first `fread` you do not print anything. That's why you don't See the first line. Nothing wrong with file content. – Gerhardh Jan 31 '19 at 07:33
  • 1
    You also use `fp` before you check for `NULL`. – Gerhardh Jan 31 '19 at 07:35

3 Answers3

2

You can use fseek() to make your purpose done. fseek() is used to move file pointer associated with a given file to a specific position.

FILE *fp;
fp = fopen("test.txt", "r");
// Moving pointer to end
fseek(fp, 0, SEEK_END);
if(ftell(fp)>0){
    printf("data exists on the file.\n");
}else{
    printf("no data.\n");
}

for more details you can read this article.

SbrTa
  • 148
  • 13
  • `fseek()` may work for my purpose, but it's not efficient for my program. I need something that is straightforward useful. – ktl159 Jan 31 '19 at 06:35
  • 1
    @KenkenCodes can you give a bit more details why you claim this to be not "straightforward useful"? – Gerhardh Jan 31 '19 at 06:54
1

Simply use ab both all cases.

If the file exists already, it will open the file and writing starts from the end of the file.

If the doesn't exists, it will be created and writing starts from the end of the file which is the same as the beginning.

From http://man7.org/linux/man-pages/man3/fopen.3.html:

   a      Open for appending (writing at end of file).  The file is
          created if it does not exist.  The stream is positioned at the
          end of the file.

EDIT

Since OP has posted more code it can be seen that the first entry will never be printed:

struct clientInfo PERSONAL;

fread((char *)&PERSONAL, sizeof(struct clientInfo), 1, fp);
^^^^^^^
Read but there is no print

system("cls");
if(fp == NULL){
    printf("Error!!!");
    getch();
}
else
{
    while((fread((char *)&PERSONAL, sizeof(struct clientInfo), 1, fp))==1)
    {
        printf("Name: %s\n", PERSONAL.Name);
    }
}

the solution is simple - just remove that fread so that fread is only done in the whileloop.

Other tips:

For gets see Why is the gets function so dangerous that it should not be used?

For fflush(stdin); see Using fflush(stdin)

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
1

The standard library also provides the stat and fstat functions that allow you to fill a struct stat to determine the file size directly. stat takes a file-path and a pointer to a stuct stat (declared with automatic storage is fine), while fstat takes an integer file-descriptor as its argument.

Using stat to determine whether the file size is greater than zero, is a simple matter of calling stat and then checking the .st_size struct member.

With appropriate validation, you could do:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define MAXC 1024

int main (void) {

    char fn[MAXC];      /* filename */
    struct stat sbuf;   /* stat buffer */
    FILE *fp;

    /* prompt, read filename, trim line-end */
    fputs ("enter filename: ", stdout);
    if (!fgets (fn, MAXC, stdin)) {
        fputs ("(user canceled input)\n", stderr);
        return 1;
    }
    fn[strcspn (fn, "\r\n")] = 0;

    /* call stat, fill stat buffer, validate success */
    if (stat (fn, &sbuf) == -1) {
        perror ("error-stat");
        return 1;
    }

    /* test sbuf.st_size to check if file size > 0 */
    if (sbuf.st_size > 0) {
        puts ("opened ab");
        fp = fopen (fn, "ab");
    }
    else {
        puts ("opened wb");
        fp = fopen (fn, "wb");
    }
    /* rest of code... */
}

Either way, using seek or stat, you can determine what you need.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85