10 - Files and Command Line Arguments

Download as pdf or txt
Download as pdf or txt
You are on page 1of 13

CS100 : Computer Programming

Chapter 12 - Files and command line arguments


Narasimhan T.

12.1 Files
So far, we have seen taking input from the user through keyboard or outputting the results
to the screen. This works fine if the frequency of I/O (input-output) operations is low. As
the volume of data to be processed increases, the I/O operations become tedious. Moreover, if
you want to repeatedly execute a program, you need to enter the input, each time you execute
it. In such situations, it becomes necessary to store the data in a manner so that they can be
easily retrieved later. One of the simplest ways for programs to organize their data is to use
data files. A file is a collection of bytes stored on a permanent medium like a hard drive, flash
memory, or CD-ROM.
Files are of two types : data files and program files. Data files store data to be processed
by a program. Program files on the other hand contain instructions or code to be executed.
Data files are further classified as text files and binary files.
A text file (also called ASCII file) stores information as ASCII characters. A text file
contains human-readable characters. A user can read the contents of a text file or edit it using
a text editor. In text files, each line of text is terminated (delimited) with a special character
known as EOL (End of Line) character. Text documents like word documents are a good example
of text files.
A binary file is a file that contains information in the binary form. Thus, such files are not
human readable but provide a better security than text files. In binary file, there is no delimiter
for a line. Binary files are faster and easier for a program to read and write than the text files.
Image files are an example of binary files. The discussion here is restricted to that of text files.

12.1.1 File operations


The usual sequence of operations on a file (whether text or binary) is:
1. Creating/opening a file
2. I/O operations - read or write
3. Closing a file
When working with files, you need to declare a pointer of type FILE. (FILE is a predefined struc-
ture that holds the relevant details about a file.) This declaration is needed for communication
between the file and the program. The pointer is called file pointer and is declared as
FILE *fp;
where fp is the name of the pointer.

1
12.1.1.1 Opening and closing files
Before you can read from or write to a file, you have to open it using the fopen() function.
The syntax of fopen() is:
fp=fopen(fileName,accessMode)
where fileName specifies the name of the file you want to open and accessMode specifies the
purpose of opening the file. For example, the following code opens a file named myfile.txt for
writing:

fp=fopen("myfile.txt",’w’)

The various access modes and their description are tabulated in Table 12.1.
While trying to open a file, the fopen() function returns a file pointer if successful. If an
error occurs, it returns a null pointer NULL.

Table 12.1: List of the different modes of opening a file

Access mode Meaning


Opens a file for reading only. Raises an error if the
r
file does not exist.
Opens a file for writing only. Overwrites the file if
w the file exists. If the file does not exist, creates a
new empty file for writing.
Opens a file for appending (i.e., for adding new
a information at the end of the file). A new empty
file will be created if the file does not exist.
Opens a file for both reading and writing. Raises
r+
an error if the file does not exist.
Opens a file for both reading and writing. If the
w+ file already exists, it will be destroyed and a new
file is created.
Opens a file for both reading and appending. A
a+ new file will be created if the file specified does
not exist.

Once you have performed the operations (read or write) on the file, you need to close it.
For this you use the fclose() function. The statement
fclose(fp);
closes a file whose associated file pointer is fp.

12.1.1.2 Reading and writing with files


C provides a plenty of functions to perform I/O on files. These functions can be formatted
functions or unformatted functions. Unformatted input/output transfers the internal binary
representation of the data directly between memory and the file. Formatted output converts
the internal binary representation of the data to ASCII characters which are written to the
output file. Formatted input reads characters from the input file and converts them to internal
form.

2
Writing characters to file
The putc() function writes characters to a file opened for writing. The syntax is
putc(ch,fp);
where fp is the pointer associated with the file to which the character ch is to be written. If a
putc() operation is successful, it returns the character written. Otherwise, it returns a special
value called EOF (End Of File).

Example 12.1. The program below writes a collection of characters one by one to a file.
#include<stdio.h>
main()
{
FILE *fp;
int count,i;char c;
fp=fopen("sample.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("How many characters you want to enter?\n");
scanf("%d",&count);
for(i=0;i<count;i++)
{
printf("Enter a character\n");
scanf(" %c",&c);
putc(c,fp);
}
fclose(fp);
}
}

Reading characters from file


The getc() function reads characters from a file opened in read mode. The syntax is
ch = getc(fp);
where ch is the integer equivalent of the character read from the file whose pointer is fp. The
getc() function returns an EOF when the end of the file has been reached.

Example 12.2. This code reads all characters in a file one by one and prints them until the
end of the file is reached.
#include<stdio.h>
main()
{
FILE *fp;
int ch;
fp=fopen("sample.txt","r");
if(fp==NULL)

3
printf("Sorry! Error in opening file\n");
else
{
while ((ch = getc(fp))!= EOF)
{
putchar(ch);
//ch = getc(fp);
}
fclose(fp);
}
}

Using feof()
getc() returns EOF when it reaches the end of the file. When an error occurs during read
operation, then also getc() returns EOF. Thus, using only the return value of getc(), it is
impossible to know which occurred. To solve this problem, C includes the function feof(),
which determines when the end of the file has been encountered. feof() returns 1 if the end
of the file has been reached; otherwise, it returns zero. Therefore, to read the characters from
a file to its end, you can use the code:
while(feof(fp)!=0)
ch = getc(fp);

Working with strings


C provides the functions fgets() and fputs() to read and write character strings from and to
a file. The syntax of fputs() is
fputs(str,fp);
where str is the string to be written to the file whose pointer is fp. The function returns EOF
if an error occurs.

Example 12.3. This example illustrates the use of fputs() function to write a string to a file.
#include<stdio.h>
main()
{
FILE *fp;
int count,i;char str[15];
fp=fopen("sampleStrP.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("Enter a string\n");
scanf(" %s",str);
fputs(str,fp);
fclose(fp);
}

4
}

The syntax of fgets() is


fgets(str,length,fp);
The fgets() function reads a string from the specified file (whose pointer is fp) until either a
newline character is read or length − 1 characters have been read. If a newline is read, it will
be part of the string. The function returns the string str if successful and a null pointer if an
error occurs.

Example 12.4. Here is how you read strings from a file using fgets().
#include<stdio.h>
main()
{
FILE *fp;
char str[50];
fp=fopen("sample.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
while ((fgets(str,50,fp))!=NULL)
printf("%s",str);
fclose(fp);
}
}

Reading and writing integers


The putw() function is used to write integers to the file. The syntax is
putw(num, fp);
The putw() function takes two arguments, first is an integer value num to be written to the file
and second, fp is the corresponding file pointer. Similarly getw() is used to read integers from
a file. The syntax is
n=getw(fp);
The getw() function takes the file pointer as argument from where the integer value will be
read and returns the read value n. It returns EOF if it has reached the end of file.

Example 12.5. The program below inputs numbers from the user and writes them to a file.
Later the numbers are printed by reading from the file.
#include<stdio.h>
main()
{
FILE *fp;
int num,count,i;

5
printf("How many numbers?");
scanf("%d",&count);
fp=fopen("file.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
for(i=0;i<count;i++)
{
printf("Enter any number:\n");
scanf("%d",&num);
putw(num,fp);
}
fclose(fp);
}
fp=fopen("file.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
num=getw(fp);
while(num!=EOF)
{
printf("%d ",num);
num=getw(fp);
}
fclose(fp);
}
}

Working with blocks of data


When processing large amounts of data, it is often easier to group information together, instead
of dealing with lots of individual variables. For example, when you are dealing with structure
variables, it would be beneficial to read/write the structure data at a single step. To read and
write data that are longer than 1 byte, the C language provides the functions: fread() and
fwrite(). These functions allow the reading and writing of blocks of any type of data.
The syntax of fwrite() is
fwrite(addr,size,count,fptr)
where

• addr denotes the address of the data block (structure variable) whose contents are to be
written to file.

• size denotes the size of the block.

• count denotes the number of data blocks (number of structure variables) that you need
to write.

6
• fptr represents the file pointer associated with the file to which you are going to write
data.

Similarly fread() is used to read blocks of data from a file. The syntax of fread() is same as
that of fwrite():
fread(addr,size,count,fptr)
where

• addr denotes the address of the data block (structure variable) to which data from the
file will be written.

• size denotes the size of the block.

• count denotes the number of data blocks (number of structure variables) whose contents
you are reading.

• fptr represents the file pointer associated with the file from which you are reading data.

Example 12.6. This example inputs the details of a bank customer and writes to the file.
Later, the contents are being read from the file and printed out.
#include<stdio.h>
typedef struct
{
char name[15];
int accNo;
float balance;
}account;
main()
{
account acc;
FILE *fp;
fp=fopen("struct.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("Enter customer name\n");
scanf(" %s",acc.name);
printf("Enter account number\n");
scanf("%d",&acc.accNo);
printf("Enter balance\n");
scanf("%f",&acc.balance);
fwrite (&acc, sizeof(account), 1, fp); /*count is 1 because you are
writing the contents of only 1 struct variable*/
fclose(fp);
}
fp=fopen("struct.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else

7
{
fread(&acc, sizeof(account), 1, fp);
printf("Customer name: %s\n",acc.name);
printf("Account number: %d\n",acc.accNo);
printf("Balance: %f\n",acc.balance);
fclose(fp);

}
}

Formatted functions
If you need to handle multiple data items and that too of mixed types (char, int, float etc.),
you should use fprintf() and fscanf(). The fprintf() function is used to write mixed type
data items into a file. Its syntax is
fprintf(fp,format-string,var-list);
where fp is the file pointer, format-string is the list of format specifiers and var-list is the
list of variables whose values are to be written to file. Thus fprintf() function is similar to
printf() function except the first argument which is a file pointer.
The fscanf() function is used to read mixed type data from the file. The syntax is similar to
that of fprintf():
fscanf(fp,format-string,addr-list);
where fp and format-string have same meanings as with fprintf(); addr-list denotes the
lists of addresses of variables which will hold the values that are read from the file.
Example 12.7. The code below inputs the details of a student and writes them to a file. The
details are then printed by reading from the file.
#include<stdio.h>
main()
{
int m1,m2,roll,n,i;
char name[15];
FILE *fp;
fp=fopen("marks.txt","w");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
printf("Number of students please\n");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Enter the details of student %d\n",i+1);
scanf(" %s %d %d %d",name,&roll,&m1,&m2);
fprintf(fp,"%s %d %d %d",name,roll,m1,m2);
}
fclose(fp);

8
}
fp=fopen("marks.txt","r");
if(fp==NULL)
printf("Sorry! Error in opening file\n");
else
{
for(i=0;i<n;i++)
{
printf("Details of student %d\n",i+1);
fscanf(fp,"%s %d %d %d",name,&roll,&m1,&m2);
printf("Name: %s\n",name);
printf("Roll: %d\n",roll);
printf("Marks: %d and %d\n",m1,m2);
}
fclose(fp);
}
}

12.1.2 Random access to files


If you want to access specific locations in a file, C supports three functions for random access
to files.

12.1.2.1 ftell()
This function tells the current position of the file pointer in the file. It takes a file pointer as
argument and returns the byte location of current position of the pointer. The statement
len = ftell(fp);
means that the file pointer is currently at byte numbered len. i.e., bytes 0 to len - 1 are to
the left of the current pointer position.

12.1.2.2 rewind()
The rewind() function resets the file pointer to the beginning of the file with the pointer
specified as its argument. That is, it “rewinds” the file. Its syntax is:
rewind(fp);
where fp is a file pointer. Thus, after executing the statements,
rewind(fp);
n=ftell(fp);
the value of n will be zero (indicating the beginning of file).

12.1.2.3 fseek()
fseek() is used to move the file pointer to a desired location in the file. Its syntax is:
fseek(fp,offset,position);

9
where
• fp is the file pointer.
• offset is the number of bytes fp is to be moved.
• position denotes the position from which the file pointer is moved.
position can take three values:
• 0 – beginning of file
• 1 – current position
• 2 – end of the file
position can also be specified in terms of constants rather than in terms of integers as follows:
• SEEK SET – beginning of file
• SEEK CUR – current position
• SEEK END – end of the file
offset can be positive or negative. If it is positive, the file pointer is moved in forward direction.
If it is negative, file pointer is moved backwards.
Example 12.8. This example shows some usages of fseek() function and their interpretations.
fseek(fp,0,0) − Moves fp zero bytes from the beginning of the file. In other
words, it moves the file pointer to start of the file.
fseek(fp,0,SEEK CUR) − Moves fp zero bytes from current position. In other words,
the pointer stays in its current position.
fseek(fp,0,SEEK END) − Moves fp to the file end.
fseek(fp,m,SEEK SET) − Moves fp m bytes from the beginning – sets the pointer at
(m + 1)th byte in the file.
fseek(fp,m,1) − Moves fp forward by m bytes from current position.
fseek(fp,-m,1) − Moves fp backward by m bytes from current position.
fseek(fp,-m,2) − Moves fp backward by m bytes from end of the file.

This function returns zero if successful, or else it returns a non-zero value.

12.2 Command line arguments


Sometimes it is useful to pass information into a program when you run it. Generally, you pass
information into the main() function via command line arguments. These arguments let you
control your program from outside instead of hard coding those values inside the code. Typically
command line arguments are strings that follow the command ./a.out on the terminal when
you run a program. (The discussion here is restricted to the way you run programs on Linux.)
The main() has two special built-in arguments, argc and argv, to receive command line
arguments. The argc parameter holds the number of arguments on the command line and is
an integer. It is always at least 1 because the ./a.out command itself is the first argument.
The argv parameter is an an array of character pointers. Each element in this array points to a
command line argument. More precisely, the strings at the command line are stored in memory
and address of the first string is stored in argv[0], address of the second string is stored in
argv[1] and so on. Typically, when you run programs on Linux, argv[0] is ./a.out.

10
Example 12.9. Here is a simple example that uses a command line argument. It prints Hello
and your name on the screen, if you specify your name as a command line argument.
#include<stdio.h>
main(int argc,char *argv[])
{
printf("Hello %s",argv[1]);
}
If you run the above code as follows:
./a.out Narasimhan
the output will be
Hello Narasimhan

Example 12.10. This program receives command line arguments when the program is executed
and then displays the number of arguments entered and their values.
#include<stdio.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
int i;
printf("argc is %d\n",argc);
for(i=0;i<argc;i++)
printf("argv[%d] is %s\n",i,argv[i]);
}
If you run the above code as:
./a.out CSE IT
the output is
argc is 3
argv[0] is ./a.out
argv[1] is CSE
argv[2] is IT

12.3 Programming examples


Program 12.1. To receive name, roll number and age of a student as command line arguments
and then print them.
#include<stdio.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
printf("STUDENT DETAILS\n");
if(argc<4) //You expect three values other than ./a.out

11
printf("Insufficient number of arguments\n");
else
{
printf("Name:%s\n",argv[1]);
printf("Roll:%s\n",argv[2]);
printf("Age:%s\n",argv[3]);
}
}
Recall every command line argument is a string. Thus roll number and age are interpreted as
string constants and hence %s is used while printing them.
Program 12.2. To add two numbers received as command line arguments.

#include<stdio.h>
#include<stdlib.h>
main(int argc,char *argv[])
{
int a,b;
a=atoi(argv[1]);
b=atoi(argv[2]);
printf("The sum is %d",a+b);
}
Since the numbers are received as command line arguments, they will be string constants. To
convert them to integers, the function atoi() is used. For this, the stdlib header file is
required.
Program 12.3. Input integers to a file “numbers.txt”. Read from this file and write the
even numbers to another file “even.txt” and odd numbers to a third file “odd.txt”. Finally
print the odd and even numbers separately by reading from corresponding files.
#include<stdio.h>
main()
{
FILE *fpn,*fpe,*fpo;
int num,count,i;
fpn=fopen("numbers.txt","w");
fpe=fopen("even.txt","w");
fpo=fopen("odd.txt","w");
if(fpn==NULL||fpe==NULL||fpo==NULL)
printf("Sorry!Error in opening file\n");
else
{
printf("How many integers you want to enter?\n");
scanf("%d",&count);
printf("Enter the integers\n");
for(i=0;i<count;i++)
{
scanf("%d",&num);
putw(num,fpn);
}

12
fclose(fpn);
fpn=fopen("numbers.txt","r");
num=getw(fpn);
while(num!=EOF)
{
if(num%2==0)
putw(num,fpe);
else
putw(num,fpo);
num=getw(fpn);
}
fclose(fpo);
fclose(fpe);
fpe=fopen("even.txt","r");
fpo=fopen("odd.txt","r");
printf("Contents of file with even numbers\n");
num=getw(fpe);
while(num!=EOF)
{
printf("%d ",num);
num=getw(fpe);
}
printf("\nContents of file with odd numbers\n");
num=getw(fpo);
while(num!=EOF)
{
printf("%d ",num);
num=getw(fpo);
}
fclose(fpo);
fclose(fpe);
fclose(fpn);
}
}

13

You might also like