0% found this document useful (0 votes)
14 views

System Prog Lecture 2 Edited

Uploaded by

ben munjaru
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

System Prog Lecture 2 Edited

Uploaded by

ben munjaru
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

ICS 3105 System Programming Lecture 2 – Input / Output

Files
• A file is a one-dimensional array of bytes.
• Regardless of what sort of data is inside a file, it is always stored as a one dimensional array of
bytes.
• If the file contains text, an image, a song, or an executable program, it is still a one-
dimensional array of bytes. The difference is only which bit model was used to group and
encode the bytes.
• Therefore, we can always consider the process of reading from or writing to a file as being
similar to accessing a one-dimensional array of bytes.
• A system typically provides a set of function calls, for use by programs, to interact with files.
• These include operations such as the ability to read and write data.
• A file has a beginning and an end, and it has a current position, typically defined as so many
bytes from the beginning.
• The current position is where any file action (a read from the file or a writek to the file) will
take place.
• You can move the current position to any point in the file. A new current position can be
specified as an offset from the beginning of the file or, in some circumstances, as a positive or
negative offset from the previous current position.
• You can also move the position to the end of the file in some situations.

File Streams
• An I/O transaction occurs when a program receives bytes from a source or sends bytes to a
destination.
• The flow of bytes is commonly referred to as a stream
• A stream is an abstract representation of any external source or destination for data, so the
keyboard, the command line on your display, and files on a disk are all examples of things you
can work with as streams.
• You use the same input/output functions for reading from and writing to any external device
that is mapped to a stream
• The C library provides functions for reading and writing to or from data streams.
• Two ways of writing data to a stream that represents a file:
– First, you can write a file as a text file, in which case data are written as a sequence of
characters organized as lines, where each line is terminated by a newline character. Obviously,
binary data such as values of type int or type double have to be converted to characters to
allow them to be written to a text file, and you have already seen how this formatting is done
with the printf() and printf_s() functions.
– Second, you can write a file as a binary file. Data written to a binary file are written as a series
of bytes exactly as they appear in memory, so a value of type double, for example, would be
written as the 8 bytes that appear in memory.
• Of course, you can write any data you like to a file, but once a file has been written, it just
consists of a series of bytes.
• Regardless of whether you write a file as a binary file or as a text file, it ultimately ends up as
just a series of bytes. This means that the program must know what sort of data the file
represents to read it correctly.
• A sequence of 12 bytes in a binary file could be 12 characters, 12 8-bit signed integers, 12 8-
bit unsigned integers, 6 16-bit signed integers, a
32-bit integer followed by an 8-byte floating-point value, and so on.
• All of these will be more or less valid interpretations of the data, so it’s important that a
program that is reading a file has the correct assumptions about what was written.

Accessing Files
• Each of the files that are resident on your disk drive have names, and the rules for naming
files are determined by your operating system.
• Your program references a file through a file pointer or more accurately a stream pointer.
• You associate a stream pointer with a particular file programmatically when the program is
run.
• A program can associate a given stream pointer with different files on different occasions, so
the same program can work with a different file each time it executes.
• A file pointer points to a structure of type FILE that represents a stream.

File Pointer
• A file pointer is a marker used to keep track of the location for reading or writing on a stream.
• When a file is opened, the file pointer points to the first byte in the file.
• Each time a byte is read, the file pointer is automatically advanced to the next byte.
• If multiple bytes are read, then the file pointer is advanced beyond all the bytes that have
been read.
• The FILE structure to which a file pointer points contains information about the file. This will
be such things as whether you want to read or write 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.
Opening a File
• One way to open a file is by calling the fopen() function that returns the file pointer for a
specific external file.
• The fopen() function is defined in stdio.h, and it has this prototype:

• 1st argument: pointer to a string that is the name of the external file you want to process. The
argument can be an explicit name, an array, or a variable of type pointer to char that contains
the address of the character string that defines the file name.
• 2nd argument: character string that represents the file mode. The file mode specifies what
you want to do with the file.
FILE *fopen(const char * restrict name, const char * restrict mode);
• Assuming the call to fopen() is successful, the function returns a pointer of type FILE* that you
can use to reference the file in further input/output operations using other functions in the
library. If the file cannot be opened for some reason, fopen() returns NULL.
• Note the pointer returned by fopen () is referred to as either a file pointer or a stream
pointer.
• A call to fopen() does two things:
– It creates a file pointer—an address—that identifies the specific file on a disk from the name
argument you supply
– determines what you can do with that file.
• For multiple files, each file must have its own pointer variable, and each can be opened with a
separate call to fopen().
• There’s a limit to the number of files you can have open at one time, which will be
determined by the value of the symbol FOPEN_MAX that’s defined in stdio.h.
• The C standard requires that the value of FOPEN_MAX be at least eight, including stdin,
stdout, and stderr, so as a minimum you will be able to be working with up to five files
simultaneously but typically it’s many more, often 256, for example.
• The safer optional alternative function for opening files, fopen_s(), has the prototype:

• You need to define the symbol __STDC_WANT_LIB_EXT1__ as 1 to use this function. The
function fopen_s() is a little different from fopen().
– The first parameter is a pointer to a FILE structure, so you pass the address of your FILE*
variable that is to store the file pointer as the first argument.
The function will verify that the last two arguments you pass are not NULL and it will fail if
either is.
– It returns a value of type errno_t, which indicates how the operation went. Type errno_t is an
integer type that is defined by a typedef in stdio.h, often as equivalent to type int. The function
returns 0 if everything went well and a nonzero integer if it was unable to open the file for
some reason. In the latter case, the file pointer will be set to NULL.

Mode Description
“r” Open a text file for read operations.
“r+” Open a text file to read and write it.
“w” Open a text file for write operations. If the file exists, its current contents are discarded.
“wx” Create and open a text file to write it with nonshared access
“w+” Truncate an existing text file to zero length and open it for update.
If the file does not exist, create it and open it for updating.
“w+x” Create a text file for updating with nonshared access.
“a” Open or create a text file to append to it. All writes will be at the end of the file.
“a+” Open or create a text file for update, with all writes adding data at the end of the file.

Write Mode
• If you want to write to an existing text file with the name myfile.txt, you would use this
statement:

• This opens the file and associates the file with the name myfile.txt with your file pointer pfile.
• Because you’ve specified the mode as "w", you can only write to the file; you can’t read it.
The string you supply as the first argument is limited to a maximum of FILENAME_MAX
characters, where FILENAME_MAX is defined in the stdio.h. This value is usually large enough
that it isn’t a real restriction.
• If a file with the name myfile.txt does not exist, the call to fopen_s() in the previous statement
will create a new file with this name.

• Because you have just provided the file name without any path specification as the second
argument to the function, the file is assumed to be in the current directory; if the file is not
found there, that’s where it will be created.
• You can also specify a string that is the full path and name for the file, in which case the file
will be assumed to be at that location and a new file will be created there if necessary.
• Note that if the directory that’s supposed to contain the file doesn’t exist when you specify
the file path, neither the directory nor the file will be created and the fopen_s() call will fail.
• If the call to fopen_s() does fail for any reason, a nonzero integer will be returned and pfile
will be set to NULL. If you then attempt further operations with a NULL file pointer, it will cause
your program to terminate.
• On opening a file for writing, the file length is truncated to zero and the will be at the
beginning of any existing data for the first operation. This means that any data that were
previously written to the file will be lost and overwritten by any write operations.

Append Mode
• If you want to add to an existing text file rather than overwrite it, you specify mode "a", which
is the append mode of operation. This positions the file at the end of any previously written
data. If the file doesn’t exist, a new file will be created. If you want to reuse the file pointer you
declared previously to open the file to add data to the end, use the following statement:

• When you open a file in append mode, all write operations will be at the end of the data in
the file on each write operation.

Read Mode
• If you want to read a file, open it using this statement:

• You have specified the mode argument as "r", indicating that you want to read the file, so you
can’t write to this file. The file position will be set to the beginning of the data in the file.
Clearly, if you’re going to read the file, it must already exist. If you inadvertently try to open a
file for reading that doesn’t exist, fopen_s() will set the file pointer to NULL and return a
nonzero value. You should always check the value returned from fopen_s() to make sure you
really are accessing the file you want.
Buffering File Operations
• A buffer is a temporary storage between the sender and receiver of bytes on a stream.
• The buffer is an additional piece of memory location that is used to moderate the flow of
bytes from the source to the destination.
• A buffer is useful in a variety of situations:
• When the sender puts bytes into a stream faster than the receiver can handle.
• If a program is in a middle of an operation and is not prepared to receive any byte.
• The buffer can store up the bytes until the program is able to handle them, receiving them
either at a reduced rate or when it is ready for them.
• There are three basic types of buffering:
• Block buffering
• Line buffering
• And buffered
• They differ in how the temporary storage is flushed.
• Flushing is the act of emptying out the temporary storage, sending all the bytes in the buffer
on down the stream to the receiver.
• In a block buffer, fixed-size chunk of memory is filled before being passed on to the receiver.
• In a line buffer, any bytes inside the buffer are sent to the receiver once a newline character
(byte value of 13) is received.
• Finally, if the stream is unbuffered, then each byte is sent to the receiver as soon as it is
placed in the buffer.
• Once you have opened a file, you can control how input operations are buffered by calling
setvbuf(), which has the following prototype:

• The first parameter is the file pointer to an open file. You can only call setvbuf() to determine
the buffering before you have performed any other operation with the file pointed to by the
first argument.
• The second parameter specifies an array that is to be used for buffering, and the fourth
parameter is the size of the array. If you specify NULL as the second argument, setvbuf() will
allocate a buffer for you with the size you specify as the fourth argument.
• The third argument specifies the buffering mode and can be one of the following:
• _IOFBF causes the file to be fully buffered. When input and output is fully
buffered, data are written or read in blocks of arbitrary size.
• _IOLBF causes operations to be line buffered. When input and output is line
buffered, data are written or read in blocks terminated by a newline.
• _IONBF causes input and output to be unbuffered. With unbuffered input and
output, data are transferred character by character. This is extremely inefficient,
So you would only use this mode when it was essential.
• The setvbuf() returns 0 when everything is okay and a nonzero integer when it isn’t. Here’s
how you might use it for a file pointed to by pfile:

• If you just want full buffering for input or output, you can call setbuf(), which has this
prototype:

• The first parameter is the file pointer and the second is the address of an array to be used as a
buffer. The second argument can be NULL, which I recommend, in which case the buffer will be
created for you. If you specify buffer, its length must be BUFSIZ bytes, where BUFSIZ is defined
in stdio.h.
• Here’s how you might buffer operations for a file with the pointer pfile using your own buffer:

• Note that you must ensure that your buffer continues to exist as long as the file is open. This
implies that you must take great care when you use an automatic array that will expire at the
end of the block in which you create it. If the second argument to setbuf() is NULL, the file
operations will not be buffered.

Renaming a File
• Renaming a file is very easy. You just use the rename() function, which has the following
prototype:

• The integer that’s returned will be 0 if the name change was successful and nonzero
otherwise. The file must not be open when you call rename(), otherwise the operation will fail.
• Here’s an example of using the rename() function:
Closing a File
• When you’ve finished with a file, you need to tell the operating system that this is the case
and free up the file so it can be used by others. This is referred to as closing a file. You do this by
calling the fclose() function that accepts a file pointer as an argument and returns a value of
type int, which will be EOF if an error occurs and 0 otherwise. The typical usage of the fclose()
function is as follows:

• The result of calling fclose() is that the connection between the pointer, pfile, and the physical
file is broken, so pfile can no longer be used to access the file it represented. If the file was
being written, the current contents of the output buffer are written to the file to ensure that
data are not lost. It’s good practice to always set the file pointer to NULL when you have closed
a file.

Example C Program - 1

• In this example, bytes are being sent down a stream using the fprintf() function.

Example C Program – 2
• In this example, bytes are being transported on a using the fscanf()
function.

You might also like