File input and output in C
Tags: c, files, pointers, beginners
Published: 2019-12-27 20:18:12

---
title: File input and output in C
published: true
description: Working with files in the C programming language
tags: C, files, pointers, beginners
series: Basics of the C programming language
---

####Overview

The difference between types of memory:
Volatile memory is what is used by the language to store and access all standard operations: functions, variables, structures, etc. Volatile memory is not persistent - it is erased when a program ends and between reboots and it is very fast to access.
Non-volatile memory is memory on the hard disk. It is slower to accesss, but it will persist between program sessions or reboots.

You can work with non-volatile memory in C, which are seen by the language as a continuous sequence of bytes. Each byte can be read individually, and the defaults correspond to the file structure in the Unix environment. It is still possible to read Windows files, there are just some extra bytes at the end of the file that need to be handled properly.

All file operations are included in `stdio.h`, so be sure to include it when working with files.

####Text and binary files

There are two ways of writing dat to a stream that represents a file: text, and binary.
Text data is written as a sequence of characters organized as lines (each line ends with a newline).
Binary data is written as a series of bytes exactly as they appear in memory, e.g. image data, music encoding.

You can write any data you like to a file - once it is written, it just consists of a series of bytes.
To read a file, you have to understand the format to interpret it, because the same number of bytes could represent a number of things, e.g. 12 bytes in a binary file could be 12 characters, 12 8-bit signed integers, 12 8-bit unsigned integers, etc.
In binary mode, every byte of the file is accessible.

####Streams

Streams are a more generic term, and can represent many types of input:

- standard input: normal input device for your system, usually a keyboard
- standard output: usually the display/screen
- standard error: usually output to the screen

Standard input is the the file that is read by `getchar()` and `scanf()`.
Standard output is used by `putchar()`, `puts()`, and `printf()`.
Redirection causes other files to be recognized as standard input or standard output.

The purpose of the standard error output file is to provide a logically distinct place to send error messages.
A stream is an abstract representation of any external source or destination for data. The keyboard, command line on the display, and files on a disk are all examples of things you can work with as streams. The C standard libraries provides functions for reading and writing to or from data streams.
You can also use the same input/output functions for working with any external device that is mapped to a stream.

####Accessing files

Files on disk have a name, and the rules for naming files are determined by the OS used. A program references a file through a file pointer (or stream pointer, since it works on more than a file). You associate a file pointer with a file programmatically when the program is run, and pointers can be reused to point to different file son different occasions.

A file pointer points to a structure of type FILE that represents a stream, which contains the following information about the file:

- whether you want to read or update the file,
- the address of the buffer in memory to be used for data, and
- a pointer to the current position in the file for the next operation.

If you want to use several files simultaneously in a program, you need a separate file pointer for each file, and there is a limit on the number of files you can have open at one time, defined as FOPEN_MAX in `stdio.h`.

####Opening a file

Under the hood, opening a file is: associating an external file name with an internal file pointer variable.
Use the fopen() function to open a file, which will return the pointer for a specific external file (on the disk). The syntax:

```c
FILE *fopen(const char * restrict name, const char * restrict mode);
```

The first argument is a pointer to a string that is the name of the external file you want to process. You can specify the name explicitly or use a char pointer that contains the address of the character string that defines the file name. You can obtain the file name through the command line, as input from the user, or defined as a constant in your program.
The second argument to `fopen()` is a character string that represents the mode, in double quotes, and is the same as most other languages.

| mode |                                                 operation                                                 |
| :--: | :-------------------------------------------------------------------------------------------------------: |
|  R   |                                                 read only                                                 |
|  R+  |                                              read and write                                               |
|  W   |          write only. Overwrites the file if there is text, and creates a file if there is none.           |
|  W+  | Open a file to read and write. Overwrites the file if there is text, and creates a file if there is none. |
|  A   |                            append. Writes all changes to the end of the file.                             |
|  A+  |                            append and read. Creates a new file if none exists.                            |

The file path is relative unless an absolute path is provided.

Assuming the call to `fopen()` is successful, the function returns a pointer to type `FILE*` that you can use to reference the file in further input/output operations using the other functions in the library. If a file cannot be opened for some reason,`fopen()` returns NULL, so it's best to run an `if` check, as with pointer creation.

Examples:

```c
// write mode
FILE *pfile == NULL;
char *filename = "myFile.txt";
  //open myFile to write to it
pfile = fopen(filename, "W");
  // if the file does not exist, then it will be created. It is still a good idea
  // to check that it does not return NULL (an error) with an if statement
if(!filename)
{
  printf("Failed to open %s", filename);
}


// read mode
pfile = fopen(filename, "R");
  // check that it does not return NULL (an error) with an if statement
if(!filename)
{
  printf("Failed to open %s", filename);
}

// append mode
pfile = fopen(filename, "A");
  // if the file does not exist, then it will be created. It is still a good idea
  // to check that it does not return NULL (an error) with an if statement
if(!filename)
{
  printf("Failed to open %s", filename);
}
```

To add the extra mode (i.e. make it read and write), add the `+` plus at the end of the mode inside the quotes.

#####Renaming files
The file cannot be open when you call `rename()` or the operation will fail. Use an `if` to check that there are no errors.
Renaming a file is easy using the `rename()` function.

```c
int rename(const char *oldName, const char *newName);
// check for failure
if(rename("~/coding/c/oldName.txt", "~/coding/c/newName.txt"))
{
printf("File renamed.");
}
else
{
printf("Failed to rename file.");
}
```

Note on Windows files:
Because Windows uses the same character `\` as the escape character in C for file paths, all the paths when dealing with windows will need an extra forward slash to escape the forward slash of the filename:
`C:\\myProgram\\myFile.txt`

####Closing a file

When you are finished with a file, you must close it to free up the file and resources. Use the fclose() function, and it takes one arguments: a pointer to a file. It returns EOF (end of file -- an int) if an error occurrs. It is defined in `stdio.h` as a negative integer that is usually equivalent to the value of -1.
`fclose()` returns 0 if successful.

```c
fclose(pfile);
// set the value of the pointer to NULL after the file is closed
pfile = NULL;
```

The result of calling `fclose()` is that the connection between the pointer, pfile, and the physical file is broken, and pfile can no longer be used to access that file (unless it is reassigned). It is good practice to always close a file immediately after you are done using it - which protects against data loss. You must also close a file before renaming, or deleting.
If the file was being written, the current contents of the output buffer are written to the file to ensure that the data is not lost, which is a nice bit of security to have when writing to files.

####Deleting a file

Use the `remove()` function to delete a file. It takes the filename as an argument (not a pointer), since it cannot be open when deleting it. This is your standard warning that with great power comes great responsibility - only delete files if you are absolutely sure it is safe to do so - they cannot be recovered.