• C

Structures to file

I'm creating a database to help reinforce some of the basic ideas that I've learned in C.  I'm using a structure to store the info.  I've come across scripts that allow me to write structures out to a file, but none that show me how I can append a single record to this file without reloading the entire structure from the file.  Also, when I do load the entire database back into a structure, how can I determine how many records (this is an array of structures) have been read into my array of structures ?
tkw829Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

kellyjjCommented:
one way to do this is:

fh=fopen("test.txt","wr");

while (!eof(fh)) fread(buffer,1,sizeof(struct),fh);

fwrite(struct,1,sizeof(struct),fh);

now to keep track of how many records are read into simply keep a counter of each read:

while (!eof(fh))
{
  num_of_recs=num_of_recs+1;
  fread(buffer,1,sizeof(struct),fh);
}


I hope this helps you get going.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
RONSLOWCommented:
open the file for append.

0
alexoCommented:
Use fseek() to position your pointer at the end of the file (or any other position, if you use a multiple of sizeof() of your structure).
0
ON-DEMAND: 10 Easy Ways to Lose a Password

Learn about the methods that hackers use to lift real, working credentials from even the most security-savvy employees in this on-demand webinar. We cover the importance of multi-factor authentication and how these solutions can better protect your business!

RONSLOWCommented:
fseek of course relies on you knowing how many records are there.  To simply aapend new records, open (binary) for read/write with append should do the trick.

0
ozoCommented:
you can fseek(fh,0,SEEK_END)
(of course, append ensures that happens automatically)
0
alexoCommented:
fseek() (or it's low level counterpart lseek()) can position the pointer at the beginning of the file or end of the file without any knowledge of the file's length or contents.  Positioning the pointer in the middle of the file will work best if you land on a structure boundary :-)

Openning the file for append (mode "a" or "a+") does not allow changing existing records.  You'll need to open it for R/W access (mode "r+") for that.
0
RONSLOWCommented:
fairy nuff ozo :-)

BTW: check out strucfil.c at www.snippets.org

This does direct file i/o using fseek etc.

0
RONSLOWCommented:
here is the source for it... it is hard-coded for a struct called 'blackbook' .. but it s very good starting point!!

===========
strucfil.h:
===========
/* +++Date last modified: 05-Jul-1997 */

/*
**  SNIPPETS header file for STRUCFIL.C
*/

#ifndef STRUCFIL__H
#define STRUCFIL__H

#include <stdio.h>

/* make sure the record structure is byte aligned */

#if defined(_MSC_VER) || defined(_QC) || defined(__WATCOMC__)
 #pragma pack(1)
#elif defined(__ZTC__)
 #pragma ZTC align 1
#elif defined(__TURBOC__) && (__TURBOC__ > 0x202)
 #pragma option -a-
#endif

static struct blackbook {
    int delete_flag;        /* 0 = active  -1 = deleted */
    int recordnum;          /* a sequential number in the file */
   /* The data fields in asciiz.  */
    char firstname[11];
    char lastname[16];
    char addr[26];
    char city[16];
    char state[3];
    char zip[10];
    char phone[11];
} rec, oldrec;             /* 97 byte record  * 2 */

/* set structure alignment to default */

#if defined (_MSC_VER) || defined(_QC) || defined(__WATCOMC__)
 #pragma pack()
#elif defined (__ZTC__)
 #pragma ZTC align
#elif defined(__TURBOC__) && (__TURBOC__ > 0x202)
 #pragma option -a.
#endif

FILE * open_file(char *filename);
int    datadd(void);
int    data_delete(void);
int    data_read(long recnum);
int    data_update(void);
int    read_forward(void);
int    read_backward(void);

#endif /* STRUCFIL__H */

===========
strucfil.c:
===========

/* +++Date last modified: 05-Jul-1997 */

/*******************************************************************
 * Generic structure <> disk file manipulations. These functions
 * form a basic template for reading and writing structures to a
 * sequential file. This template is probably most useful for files
 * with 500 or less records and eliminates the need for a more
 * elaborate file handler such as C-Tree, DB-Vista, Mix etc.
 * Routines to put data in the struct is out of scope here.
 * Written by Lynn Nash 8/28/91 and donated to the public domain.
 */
#include <io.h>
#include <string.h>
#include <stdlib.h>
#include "sniptype.h"
#include "strucfil.h"
 
/*-------------------- general globals ---------------------*/

static long cur_rec = 0;      /* the current record number */
static FILE *fsptr = NULL;    /* fixed record data file pointer */
 
/* if file exists open in read/write mode else create file */

FILE * open_file(char *filename)
{
      if (access(filename, 0) == 0)
            fsptr = fopen(filename, "rb+");
      else  fsptr = fopen(filename, "wb+");
      return fsptr;                       /* return the file pointer */
}
 
/* add new records to the data file */

int datadd(void)
{
      if (fsptr)
      {
            if (fseek(fsptr, 0L, SEEK_END) != 0)
                  return Error_;  /* seek failure */
            rec.delete_flag = 0; /* active record tag */
            rec.recordnum = (int) (ftell(fsptr) /
                  (long) sizeof(struct blackbook));
            if (fwrite(&rec, sizeof(struct blackbook), 1, fsptr) != 1)
            {
                  return Error_; /* write error */
            }
            else
            {
                  /* put your clean up code here */
                  return Success_;
            }
      }
      return Error_;
}

/* tag the last record read in the file as deleted */

int data_delete(void)
{
      if (fsptr)
      {
            if (fseek(fsptr, (long) sizeof(struct blackbook) * -1L,
                  SEEK_CUR) != 0)
            {
                  return Error_;
            }
            rec.delete_flag = -1;   /* tag the record as deleted */
            if (fwrite(&rec, sizeof(struct blackbook), 1, fsptr) != 1)
                  return Error_;
            else  return Success_;
      }
      return Error_;
}

/* read a random structure. If successful the global cur_rec will
 * contain the number of the last record read & it can be compared
 * to the number in the struct as a double check (belt & suspenders)
 */

int data_read(long recnum)
{
      if (fseek(fsptr, (long) sizeof(struct blackbook) * recnum,
            SEEK_SET) != 0)
      {
            return Error_;
      }
      cur_rec = recnum; /* keep tabs on record pointer in global */  

      /* now read the record into save struct*/

      if (fread(&oldrec, sizeof(struct blackbook), 1, fsptr) != 1)
      {
            return Error_;
      }
      else                          /* copy save struct to edit struct */
      {
            memcpy(&rec, &oldrec, sizeof(struct blackbook));
            return Success_;
      }
}
 
/* rewrite the last read record back to disk */

int data_update(void)
{
      if (memcmp(&rec, &oldrec, sizeof(struct blackbook)) == 0)
            return True_;  /* no update needed */

      /* back up one record before writing */

      if (fseek(fsptr, (long) sizeof(struct blackbook) * -1L,
            SEEK_CUR) != 0)
      {
            return Error_; /* seek error */
      }

      /* now write the record */

      if (fwrite(&rec, sizeof(struct blackbook), 1, fsptr) != 1)
            return Error_; /* write error */
      return Success_;
}

/* get the next valid record in the file */

int read_forward(void)
{
      do
      {
            cur_rec++; /* upcount the record number */
            if (data_read(cur_rec) != 0)
            {
                  cur_rec--; /* decrement the record number */
                  return Error_;
            }
      } while (oldrec.delete_flag != 0); /* record read was deleted */
      return Success_;
}

/* get the previous valid record in the file */

int read_backward(void)
{
      do
      {
            cur_rec--;  /* decrement the record number */
            if (cur_rec >= 0)
            {
                  if ( data_read(cur_rec) != 0 )
                  {
                        cur_rec++; /* increment the record number */
                        return Error_;
                  }
            }  
      } while (oldrec.delete_flag != 0); /* record read was deleted */
      return Success_;
}

0
tkw829Author Commented:
Thanks kelly!!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.