Created: 2023-08-21 15:52
Status: #concept
Subject: Programming
Tags: C Pointer Buffer (JavaScript) Bash Stream Redirection stdin stdout stdio.h

File Pointer

They are FILE * which allow us to access streams like stdin or files to print & read from them.

FILE *fp1, *fp2;
// we can declar many FILE * variables, but Operating Systems can limit the max #

Different File Formats

Before reading files, we must identify whether it is a plaintext file that can be parsed with an encoding like UTF-8 or a Binary file.

  • files may be encoded with different formats, so parsing them requires the same decoder.

Opening Files

FILE *fopen(const char *fileName, const char *mode)

  • returns a pointer to the fileName Path, otherwise NULL if it's not permitted to (see chmod).

The mode is a string that represents the behavior of the file pointer:

String (text) String (binary) Meaning
"r" "rb" Open for reading
"w" "wb" Open for writing (file need not exist)
"a" "ab" Open for appending (file need not exist)
"r+" "r+b" or "rb+" Open for reading & writing, starting at the beginning
"w+" "w+b" or "wb+" Open for reading & writing (destroy if file exists)
"a+" "a+b" or "ab+" Open for reading & writing (append if file exists)

Closing Files

int fclose(FILE *stream)

  • returns 0 if the file pointer stream was closed successfully, otherwise EOF or -1.

Writing to Files

int fprintf(FILE *stream, const char *fmt, ...args)

  • it's just like printf, but it writes to a FILE * stream.
  • stderr, stdout, stderr are all valid FILE * we can use for printing & reading.

fputs(const char *str, FILE *stream) works similarly to puts().

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

int main(void) {
  FILE *fp;
  char *FILE_NAME = "./textfiles/test.txt"; // this file needs to exist before it can open it

  fp = fopen(FILE_NAME, "r+");
  if (fp == NULL) {
    printf("Can't open %s\n", FILE_NAME);
    exit(EXIT_FAILURE);
  }

  fprintf(fp, "I'm a string inside the %s file!", FILE_NAME);

  fclose(fp);
  return 0;
}

Reading From Files

char *fscanf(FILE *stream, const char *fmt, ...args)

  • Is similar to scanf, but reads the entire file, so we should add \n to the fmt Format String.

Does not scan white space characters between each word, so we should use fgets(char *dest, int bufferSize, FILE *stream).

  • the bufferSize is the STR_LEN-1 of the char *dest variable to store the string in.

Parsing Binary Data

When we use the wb mode string, the file contents are written as binary and must be read in the same way.

  • we have to specify the byte size of each chunk being read.

Assuming these type definitions:

typedef struct {
  char FN[24];
  char MI;
  char LN[16];
} Nametype;

typedef struct {
  Nametype name;
  int ID;
  char course[8];
  int yrLevel;
} Studtype;

Reading fread

FILE *fp = fopen("students.dat", "rb");

if (fp == NULL) {
  fclose(fp);
  printf("\n'%s' does not exist", fileToRead);
} else {
  Studtype current;

  while (fread(&current, sizeof(Studtype), 1, fp) != 0) {
    printf("%d", current.ID);
    displayStudent(current);
  }
}

Writing fwrite

#define MAX 10

for (int i = 0; i < MAX; i++) {
  scanf("%f", &buffer);
  fwrite(&buffer, sizeof(float), 1, fp);
}

fclose(fp);

References