Topic : Files and Folders
Author : LUPG
Page : 1 Next >>
Go to page :


Manipulating Files And Directories In Unix


-Who Is This For?
-General Unix File System Structure
-Standard "C" File Read And Write
-The FILE Structure
-Opening And Closing A File
-Reading From An Open File
-Writing Into An Open File
-Moving The Read/Write Location In An Open File
-A Complete Example
-Accessing Files With System Calls
-The Little File Descriptor That Could
-Opening And Closing File Descriptors
-Reading From A File Descriptor
-Writing Into A File Descriptor
-Seeking In An Open File
-Checking And Setting A File's permission modes
-Checking A File's Status
-Renaming A File
-Deleting A File
-Creating A Symbolic Link
-The Mysterious Mode Mask
-A Complete Example
-Reading The Contents Of Directories
-The DIR And dirent Structures
-Opening And Closing A Directory
-Reading The Contents Of A Directory
-Rewinding A Directory For A Second Scan
-Checking And Changing The Working Directory
-A Complete Example




Who Is This For?
The following tutorial describes various common methods for reading and writing files and directories on a Unix system. Part of the information is common C knowledge, and is repeated here for completeness. Other information is Unix-specific, although DOS programmers will find some of it similar to what they saw in various DOS compilers. If you are a proficient C programmer, and know everything about the standard I/O functions, its buffering operations, and know functions such as fseek() or fread(), you may skip the standard C library I/O functions section. If in doubt, at least skim through this section, to catch up on things you might not be familiar with, and at least look at the standard C library examples.




General Unix File System Structure
In the Unix system, all files and directories reside under a single top directory, called root directory, and denoted as "/". Even if the computer has several hard disks attached, they are all combined in a single directories tree. It is up to the system administrator to place all disks on this tree. Each disk is being connected to some directory in the file system. This connection operation is called "mount", and is usually done automatically when the system starts running.

Each directory may contain files, as well as other directories. In addition, each directory also contains two special entries, the entries "." and ".." (i.e. "dot" and "dot dot", respectively). The "." entry refers to the same directory it is placed in. The ".." entry refers to the directory containing it. The sole exception is the root directory, in which the ".." entry still refers to the root directory (after all, the root directory is not contained in any other directory).

A directory is actually a file that has a special attribute (denoting it as being a directory), that contains a list of file names, and "pointers" to these files on the disk.

Besides normal files and directories, a Unix file system may contain various types of special files:

Symbolic link. This is a file that points to another file (or directory) in the file system. Opening such a file generally opens the file it points to instead (unless special system calls are used).
Character (or block) special file. This file represents a physical device (and is usually placed in the "/dev" directory). Opening this file allows accessing the given device directly. Each device (disks, printers, serial ports etc) has a file in the "/dev" directory.
Other special files (pipes and sockets) used for inter-process communications.




Standard "C" File Read And Write
The basic method of reading files and writing into files is by using the standard C library's input and output functions. This works portably across all operating systems, and also gives us some efficiency enhancements - the standard library buffers read and write operations, making file operations faster then if done directly by using system calls to read and write files.




The FILE Structure
The FILE structure is the basic data type used when handling files with the standard C library. When we open a file, we get a pointer to such a structure, that we later use with all other operations on the file, until we close it. This structure contains information such as the location in the file from which we will read next (or to which we will write next), the read buffer, the write buffer, and so on. Sometimes this structure is also referred to as a "file stream", or just "stream".




Opening And Closing A File
In order to work with a file, we must open it first, using the fopen() function. We specify the path to the file (full path, or relative to the current working directory), as well as the mode for opening the file (open for reading, for writing, for reading and writing, for appending only, etc.). Here are a few examples of how to use it:


/* FILE structure pointers, for the return value of fopen() */
FILE* f_read;
FILE* f_write;
FILE* f_readwrite;
FILE* f_append;

/* Open the file /home/choo/data.txt for reading */
f_read = fopen("/home/choo/data.txt", "r");
if (!f_read) { /* open operation failed. */
    perror("Failed opening file '/home/choo/data.txt' for reading:");
    exit(1);
}

/* Open the file logfile in the current directory for writing. */
/* if the file does not exist, it is being created.            */
/* if the file already exists, its contents is erased.         */
f_write = fopen("logfile", "w");

/* Open the file /usr/local/lib/db/users for both reading and writing    */
/* Any data written to the file is written at the beginning of the file, */
/* over-writing the existing data.                                       */
f_readwrite = fopen("/usr/local/lib/db/users", "r+");

/* Open the file /var/adm/messages for appending.       */
/* Any data written to the file is appended to its end. */
f_append = fopen("/var/adm/messages", "a");



As you can see, the mode of opening the file is given as an abbreviation. More options are documented in the manual page for the fopen() function. The fopen() function returns a pointer to a FILE structure on success, or a NULL pointer in case of failure. The exact reason for the failure may be anything from "file does not exist" (in read mode), "permission denied" (if we don't have permission to access the file or its directory), I/O error (in case of a disk failure), etc. In such a case, the global variable "errno" is being set to the proper error code, and the perror() function may be used to print out a text string related to the exact error code.

Once we are done working with the file, we need to close it. This has two effects:

Flushing any un-saved changes to disk (actually, to the operating system's disk cache).
Freeing the file descriptor (will be explained in the system calls section below) and any other resources associated with the open file.
Closing the file is done with the fclose() function, as follows:


if (!fclose(f_readwrite)) {
    perror("Failed closing file '/usr/local/lib/db/users':");
    exit(1);
}


fclose() returns 0 on success, or EOF (usually '-1') on failure. It will then set "errno" to zero. One may wonder how could closing a file fail - this may happen if any buffered writes were not saved to disk, and are being saved during the close operation. Whether the function succeeded or not, the FILE structure may not be used any more by the program.




Reading From An Open File
Once we have a pointer for an open file's structure, we may read from it using any of several functions. In the following code, assume f_read and f_readwrite pointers to FILE structures returned by previous calls to fopen().


/* variables used by the various read operations.            */
int c;
char buf[201];

/* read a single character from the file.                    */
/* variable c will contain its ASCII code, or the value EOF, */
/* if we encountered the end of the file's data.             */
c = fgetc(f_read);

/* read one line from the file. A line is all characters up to a new-line  */
/* character, or up to the end of the file. At most 200 characters will be */
/* read in (i.e. one less then the number we supply to the function call). */
/* The string read in will be terminated by a null character, so that is   */
/* why the buffer was made 201 characters long, not 200. If a new line     */
/* character is read in, it is placed in the buffer, not removed.      


Page : 1 Next >>