Showing posts with label File Operations. Show all posts
Showing posts with label File Operations. Show all posts

Thursday, July 26, 2012

Character Frequency and Histogram in ANSI C

In order to understand this program you must know how to operate with text files and external arguments. If you don't, the following articles may prove helpful:
1. Computing the character frequency
/*
 * Description:
 *  Computes for each character the number of occurrences in the file
 *  specified by @stream.
 * Parameters:
 *  stream - a pointer to file
 *  statistics - a pointer to a vector containing the number of occurrences
 *      of each character.
 *  Returns:
 *   Nothing
 */
void DoStatistics(FILE* stream, long* statistics)
{
   /*Initializes the variable with an arbitrary value in order to avoid
    the use of a do-while loop*/
   char temp = 0x01;
   int i;
   /*Initializes the statistics vector*/
   for(i = 0; i<UCHAR_MAX; i++)
   {
      statistics[i] = 0L;
   }
   /*Computes the number of occurences for each character*/
   while(temp!=EOF)
   {
      temp = fgetc(stream);
      statistics[(int)(temp)]++;
   }
}
/*
 * Description:
 *  Outputs to console the character statistics in the format:
 *  character <number of occurrences>. Only printable characters will
 *  be taken into consideration.
 * Parameters:
 *  statistics - a pointer to a vector containing the number of occurrences
 *      of each character.
 *  printAll - if true, all characters will appear. Otherwise only character
 *       with at least one occurrence will appear.
 *  Returns:
 *   Nothing
 */
void PrintStatistics(long* statistics, bool printAll)
{
   int i;
   for(i = 0; i<UCHAR_MAX; i++)
   {
      if(isprint(i) && ( (statistics[i]!=0) || (printAll==true) ) )
      {
         printf("%c <%ld>\n",(char)(i),statistics[i]);
      }
   }
}
In order to compute the character frequency from a file we shall use the functions above. The first will read the file character by character and populate the statistics vector. The statistics vector size should be UCHAR_MAX. The second one function will be used for printing the character frequency statistics and should receive as a parameter a pointer to the vector populated by the first function.

2.Printing the Statistics as a Histogram
/*
 * Description:
 *  Outputs to console the character statistics as a histogram.
 *  Only printable characters will be taken into consideration.
 * Parameters:
 *  statistics - a pointer to a vector containing the number of occurrences
 *      of each character.
 *  maxScaleValue - the maximum number of asterisks that could appear in
 *      the histogram. The frequency of a character in the
 *      statistics vector is scaled according to this value.
 *  printAll - if true, all characters will appear in the histogram.
 *       Otherwise only character with at least one occurrence will
 *       appear.
 *  Returns:
 *   Nothing
 */
void PrintHorizontalHistogram(long* statistics, int maxScaleValue, bool printAll)
{
   long asterisks = 0;
   long maxValue = 0;
   int i, j;
   /*Finds out the character who has the maximum number of occurrences.
    This value will be used for scaling the statistics values*/
   for(i = 0; i<UCHAR_MAX; i++)
   {
      if(isprint(i))
      {
         if(statistics[i]>maxValue)
         {
            maxValue = statistics[i];
         }
      }
   }
   /*Checks if the statistics vector is not empty*/
   if(maxValue!=0)
   {
      for(i = 0; i<UCHAR_MAX; i++)
      {
         /*Will output information only for characters with at least
         one occurrence if the printAll option is not set. Otherwise
         will output information for all printable characters*/
         if(isprint(i) && ( (statistics[i]!=0) || (printAll==true) ) )
         {
            /*Computes the number of asterisks that will be printed.*/
            asterisks = (statistics[i]*maxScaleValue)/ maxValue;
            /*Prints the character*/
            putchar(i);
            putchar(' ');
            /*Prints a number of asterisks proportional with the number
            of occurrences*/
            for(j = 0; j<asterisks; j++)
            {
               putchar('*');
            }
            putchar('\n');
         }
      }  
   }
   else
   {
      puts("The statistics vector is empty");
   }
}
This function will print the character frequency statistics as a horizontal histogram.

3.Example
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
#include <ctype.h>

#define NR_ARGS        2
#define FILE_ARG_INDEX 1

void DoStatistics(FILE* stream, long* statistics);
void PrintStatistics(long* statistics, bool printAll);
void PrintHorizontalHistogram(long* statistics, int maxScaleValue, bool printAll);

/*
 * Description:
 *  The program will output the number of occurrences of all printable
 * characters in file.
 */
int main(int argc, char** argv)
{
    FILE* stream = NULL;
    long statistics[UCHAR_MAX];
    if(argc==NR_ARGS)
    {
       stream = fopen(argv[FILE_ARG_INDEX],"r");
       if(stream!=NULL)
       {
          DoStatistics(stream,statistics);
          PrintStatistics(statistics,false);
          PrintHorizontalHistogram(statistics,70,false);
       }
       else
       {
          perror("Could not open file");
       }
    }
    else
    {
       perror("Incorrect number of arguments");
    }
    return 0;
}

The example program above will open a text file and store the character frequency statistics in the statistics vector. After that it will print the character frequency values and build a histogram.

If we consider a file with the following text:

Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.

The output of the program for a file containing this text will be:
  <174>
" <6>
( <1>
) <1>
, <13>
- <1>
. <21>
0 <10>
1 <13>
2 <4>
3 <7>
4 <3>
5 <3>
9 <1>
B <4>
C <7>
E <3>
F <2>
G <1>
H <2>
I <6>
L <9>
M <3>
R <3>
S <2>
T <4>
V <1>
a <50>
b <12>
c <31>
d <29>
e <85>
f <19>
g <10>
h <23>
i <59>
k <6>
l <27>
m <34>
n <49>
o <79>
p <19>
r <63>
s <54>
t <53>
u <28>
v <5>
w <4>
x <3>
y <11>
  **********************************************************************
" **
(
)
, *****
-
. ********
0 ****
1 *****
2 *
3 **
4 *
5 *
9
B *
C **
E *
F
G
H
I **
L ***
M *
R *
S
T *
V
a ********************
b ****
c ************
d ***********
e **********************************
f *******
g ****
h *********
i ***********************
k **
l **********
m *************
n *******************
o *******************************
p *******
r *************************
s *********************
t *********************
u ***********
v **
w *
x *
y ****
Feel free to experiment by only counting the occurrences of digits, letters or punctuation (this can be easily done by modifying the int isprint(char c) condition with another one).

Character, Line and Word Counting in Text Files using ANSI C

To understand this tutorial you probably should know a little bit about how to operate with text files and external arguments. If you don't, read the following articles:

1. Counting characters
/* Description:
 * Counts the number of characters existing in the file specified by @stream.
 * Parameters:
 * stream - a pointer to a text file
 * Returns:
 *  The number of characters in the file.
 * Postconditions:
 *  The file pointer will be positioned at the end of the stream.
 */
long CountCharacters(FILE* stream)
{
    long counter = 0L;
    char c = 0x01;
    /*Counts until the cursor reaches EOF*/
    while(c!=EOF)
    {
        c = fgetc(stream);
        counter++;
    }
    return counter;
}
The function will return a long variable in order to avoid possible counter overflows caused by large files. The char variable c is initialized to an arbitrary variable so I could use a while loop instead of a do/while loop. The loop will be exited when the file cursor will reach the EOF (End of File) character.

2. Counting Lines
/* Description:
 * Counts the number of lines existing in the file specified by @stream.
 * Parameters:
 * stream - a pointer to a text file
 * Returns:
 *  The number of lines in the file.
 * Postconditions:
 *  The file pointer will be positioned at the end of the stream.
 */
long CountLines(FILE* stream)
{
 /*The counter is initialized to 1 because it will not count the first
  line*/
    long counter = 1L;
    char c = 0x01;
    /*Counts until the cursor reaches EOF*/
    while(c!=EOF)
    {
        c = fgetc(stream);
        /*Checks if it encounters and a newline character*/
        if(c=='\n')
        {
            counter++;
        }
    }
    return counter;
}
The same rules apply as above with the exception that the counter starts at 1 in order to include the first line. Also, the counter is only incremented when an '\n' (newline) character is encountered.

3.Counting Words
/* Description:
 * Counts the number of words existing in the file specified by @stream.
 * Parameters:
 * stream - a pointer to a text file
 * Returns:
 *  The number of words in the file.
 * Preconditions:
 *  We assume that after every punctuation mark and word delimiter there is a
 *  whitespace character.
 * Postconditions:
 *  The file pointer will be positioned at the end of the stream.
 */
long CountWords(FILE* stream)
{
    long counter = 0L;
    char c = 0x01;
    bool isInsideWord = true;
    while(c!=EOF)
    {
        c = fgetc(stream);
        if(isInsideWord==true)
        {
         counter++;
         isInsideWord = false;
        }
        else if(isspace(c))
        {
         isInsideWord = true;
        }
    }
    return counter;
}
We shall use the boolean variable isInsideWord in order to memorize the state of the file pointer. If a whitespace character was read, the state of isInsideWord will be toggled (will signify either the start or the end of a word).

I assumed that the text is written correctly and there no construction such as "There is no space after this point.Cool!". I tested the function with various text files and it gives results close to the word counter provided by LibreOffice.

4.Example
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

#define NR_ARGS        2
#define FILE_ARG_INDEX 1

#include<stdio.h>

long CountCharacters(FILE* stream);
long CountLines(FILE* stream);
long CountWords(FILE* stream);

/*
 * Description:
 *  The program prints the number of characters, lines and words existing
 *  in a text file. It should be called like:
 *   Counter file.txt
 */
int main(int argc, char** argv)
{
 FILE* stream = NULL;
 long characters = 0UL, lines = 0UL, words = 0UL;
 if(argc==NR_ARGS)
 {
     stream = fopen(argv[FILE_ARG_INDEX],"rt");
     if(stream!=NULL)
     {
         characters = CountCharacters(stream);
         /*The function positions the cursor at the end of the
          stream. In order to count correctly the cursor should
          positioned at the start of the stream*/
         rewind(stream);
         lines = CountLines(stream);
         /*The function positions the cursor at the end of the
          stream. In order to count correctly the cursor should
          positioned at the start of the stream*/
         rewind(stream);
         words = CountWords(stream);
         /*The function positions the cursor at the end of the
          stream. In order to count correctly the cursor should
          positioned at the start of the stream*/
         rewind(stream);
         printf("Characters: %ld\n"
                "Lines     : %ld\n"
                "Words     : %ld\n",
                characters,lines,words);
         fclose(stream);
     }
     else
     {
         perror("Could not open file");
     }
 }
 else
 {
     perror("Incorrect number of arguments");
 }
 return 0;;
}


Friday, July 20, 2012

Simple File Copy Algorithm in ANSI C

The simplest implementation for creating a copy of a file is to copy the original file character by character into the new file.

Against all my expectations, I managed to create a copy of a 365 Mb file in under 40 seconds on my on my modest laptop running Ubuntu 12.04.

The program takes as arguments the path to the source file (first argument) and the path to the destination file (second argument).
#include<stdio.h>

/*The number of arguments that the program takes*/
#define ARG_NUMBER            3
/*The argument index for the source file path*/
#define SOURCE_ARG_INDEX      1
/*The argument index for the destination file path*/
#define DESTINATION_ARG_INDEX 2

/*Description:
 * The program does copies a file to another.It receives as arguments
 * the path to the source file and the path to the destination file.
 */
int main(int argc, char** argv)
{
    FILE *sourceStream = NULL, *destinationStream = NULL;
    char c;
    /*Verifies if the program received a correct number of arguments*/
    if (argc == ARG_NUMBER)
    {
        /*Opens a stream to the source file*/
        sourceStream = fopen(argv[SOURCE_ARG_INDEX], "rt");
        /*Checks if the stream was successfully established*/
        if (sourceStream != NULL)
        {
            /*Opens a stream to the destination file*/
            destinationStream = fopen(argv[DESTINATION_ARG_INDEX], "wt");
            /*Checks if the stream was successfully established*/
            if (destinationStream != NULL)
            {
                /*Copies the source file into the destionation file*/
                while (feof(sourceStream) == 0)
                {
                    c = fgetc(sourceStream);
                    fputc(c, destinationStream);
                }
                /*Closes the streams*/
                fclose(sourceStream);
                fclose(destinationStream);
            }
            else
            {
                perror("Could not open destination file.");
            }
        }
        else
        {
            perror("Could not open source file.");
        }
    }
    else
    {
        perror("Incorrect number of arguments. You should provide the "
                "path to the sourceStream file and the destinationStream file");
    }
    return 0;
}

Binary File I/O in ANSI C

The ANSI C library stdio.h provides functions for reading and writing binary files. If you are not familiar with stream operations in ANSI C you should read this first.

size_t fread(void *array, size_t size, size_t count, FILE *stream)
Description:
The function reads from the stream into the array count objects of the size size.
Returns:
The function returns the number of read objects. This number may be smaller than the requested number of objects.

size_t fwrite(const void *array, size_t size, size_t count, FILE *stream)
Description:
The function writes to the stream count objects of the array having the size size.
Returns:
The function returns the number of written objects. If the return value is smaller than count, then an error happened.

Example
#include<stdio.h>

#define MAX_NAME_SIZE    80
#define MAX_EMAIL_SIZE   60
#define MAX_PERSONS      10

typedef struct
{
   char name[MAX_NAME_SIZE];
   int age;
   double salary;
   char email[MAX_EMAIL_SIZE];
}Person;

int main(void)
{
   Person persons[MAX_PERSONS] =
   {
       {"Clark Kent", 30, 3250.5, "superman@krypton.com"},
       {"Peter Griffin", 40, 1250.0, "birdmaster@familyguy.com"},
       {"Stewie Griffin", 3, 50000.0, "world_domination@familyguy.com"},
       {"Eric Cartman", 12, 50000.0, "autoritah@southpark.com"},
       {"Zapp Brannigan", 30, 200.5, "stargeneral@futurama.com"},
   };
   Person pCopy[MAX_PERSONS];
   FILE* f = NULL;
   int i;
   /*Opens the stream in <writing binary> mode*/
   f = fopen("persons.bin","wb");
   if(f!=NULL)
   {
      /*Writes 5 Person objects into the binary file*/
      fwrite(&persons, sizeof(Person), 5, f);
      /*Closes the stream*/
      fclose(f);
      /*Reopens the stream in <read binary> mode*/
      f = fopen("persons.bin","rb");
      if(f!=NULL)
      {
         /*Reads 5 Person objects from the binary file into another vector*/
         fread(&pCopy,sizeof(Person),5,f);
         /*Prints the results*/
         for(i = 0; i<5; i++)
         {
            printf("%s %d %f %s\n",pCopy[i].name,pCopy[i].age,
                                   pCopy[i].salary,pCopy[i].email);
         }
         /*Closes the stream*/
         fclose(f);
      }
   }
   return 0;
}

File Positioning Functions in ANSI C

The ANSI library stdio.h provides 5 functions that can be used for file positioning:

int fseek(FILE *stream, long offset, int origin)
Description:
The function sets the current position for stream. A subsequent read or write will access data at the beginning of the new position. The functions takes as parameters a pointer to the accessed file (stream) and two other parameters which will determine the new position (offset and origin). 

The parameter origin represents the reference which will be used for the new position. The parameter may be SEEK_SET (the beginning of the file), SEEK_CUR (current position) or SEEK_END (the end of the file).

The parameter offset represents the offset from origin in bytes. 
Returns:
The function returns a non-zero value when it encountered an error. Otherwise it returns 0.

long ftell(FILE *stream)
Description:
The function returns the current cursor position for stream.
Returns:
The current cursor position in the stream if the operation was successful. Otherwise it returns -1.

void rewind(FILE *stream)
Description:
Puts the file positioning cursor at the start of the file.

int fgetpos(FILE *stream, fpos_t *position)
Description:
The function records in position the current position in stream so it can be used later by int fsetpos(FILE *stream, const fpos_t *ptr).
Returns:
The function returns 0 if it the operation was successful. Otherwise it returns a non-zero value.

int fsetpos(FILE *stream, const fpos_t *position)
Description:
The function positions the stream according to the position. The position is obtained by calling the function int fgetpos(FILE *stream, fpos_t *position).
Returns:
The function returns 0 if it the operation was successful. Otherwise it returns a non-zero value.

Example:
Let us suppose that we have a file "file.txt" with the following content:
123456789
987654321
#include<stdio.h>
/*Legend:
 * The stream cursor will be represented with
 * the letter C.
 */
int main(void)
{
   FILE* f = fopen("file.txt","rt");
   char c;
   long result;
   int i;
   fpos_t position;

   /*Positions the cursor at:
      123C456789\n
      987654321
      The next read character will be 4*/
   fseek(f,3,SEEK_SET);
   c = fgetc(f);
   putchar(c);

   /*Positions the cursor at:
      12C3456789\n
      987654321
      The next read character will be 3*/
   fseek(f,-2,SEEK_CUR);
   c = fgetc(f);
   putchar(c);

   /*Positions the cursor at:
      123456789\n
      98765432C1
      The next read character will be 1*/
   fseek(f,-1,SEEK_END);
   c = fgetc(f);
   putchar(c);

   /*The cursor is now positioned at:
      123456789\n
      987654321C
      The indicated position will be 19 (the end of the file)*/
   result = ftell(f);
   printf("\nCurrent position: %ld",result);

   /*Puts the cursor at the begining of the file*/
   rewind(f);
   /*The cursor is now positioned at:
      C123456789\n
      987654321
      The indicated position will be 19 (the end of the file)*/
   result = ftell(f);
   printf("\nCurren position: %ld\n",result);

   /*Moves the cursor 3 positions (bytes)*/
   for(i = 0; i<3; i++)
   {
      c = fgetc(f);
   }
   /*The cursor is now positioned at:
       123C456789\n
       987654321
   */
   fgetpos(f,&position);
   /*Moves the cursor another 3 positions (bytes)*/
   for(i = 0; i<3; i++)
   {
      c = fgetc(f);
   }
   /*The cursor is now positioned at:
       123456C789\n
       987654321
       The last read character was 6
   */
   putchar(c);
   /*Positions the cursor at the memorized position*/
   fsetpos(f,&position);
   /*The cursor is now positioned at:
        123C456789\n
        987654321
        The next read character will be 4.*/
   c = fgetc(f);
   putchar(c);

   fclose(f);
   return 0;
}

Reading and Writing Structures from/to Text Files in ANSI C

The only way to keep a program's data after exiting the program is to write the data in a file. By writing the program's data into a file you will be able to use it next time you start the program.

Let us suppose that we have a structure Person with the following attributes:
-Name (string) (the string can contain spaces)
-Age (integer)
-Salary (real)
-Email (string) (cannot contain spaces)

We shall consider a simple program that writes into a text file a struct vector of the Person type and then loads from the same text file the data into a new struct vector of the Person type.
#include<stdio.h>
#include<string.h>

/*The size of the buffer used for reading from the text file*/
#define BUFFER_SIZE   250
/*The maximum size of the name field in the Person struct*/
#define MAX_NAME_SIZE    80
/*The maximum size of the email field in the Person struct*/
#define MAX_EMAIL_SIZE   60
/*The maximum number of persons*/
#define MAX_PERSONS      10
/*The relative path to the file where you can find the text file*/
#define PATH_TO_TXT_FILE "persons.txt"
/*The character who will be used to replace the space character*/
#define SPACE_REPLACEMENT   '$'

typedef struct
{
   char name[MAX_NAME_SIZE];
   int age;
   double salary;
   char email[MAX_EMAIL_SIZE];
}Person;

/*
 * Description:
 *  Replaces all occurrences of @replacedChar with @replacementChar
 * Parameters:
 *  string - the string where the replacement process will take place
 *  replacedChar - the character who will be replaced
 *  replacementChar - the character who will replace the @replacedChar
 * Returns:
 *  Nothing
 */
void ReplaceChar(char* string, char replacedChar, char replacementChar)
{
   int size = strlen(string);
   int i;
   for(i=0; i<size;i++)
   {
      if(string[i]==replacedChar)
      {
         string[i] = replacementChar;
      }
   }
}
/*
 * Description:
 *  Outputs to stdout the content of the Person vector
 * Parameters:
 *  p - a pointer to the the Person vector
 *  numberOfPersons - how many elements the vector has
 * Returns:
 *  Nothing
 */
void Persons_Print(Person *p, int numberOfPersons)
{
   int i;
   for(i = 0; i<numberOfPersons; i++)
   {
      printf("%s %d %f %s\n",p[i].name,p[i].age,p[i].salary,p[i].email);
   }
}
/*
 * Description:
 *  Saves in the text file represented by @stream the content of the
 *  person vector.
 * Parameters:
 *  p - a pointer to the Person vector
 *  numberOfPersons - how many elements the vector has
 *  stream - a pointer to the text file
 */
void Persons_Save(Person *p, int numberOfPersons, FILE* stream)
{
   int i;
   for(i = 0; i<numberOfPersons; i++)
   {
      /*Replaces all spaces in the name string in order to be
        able to load a person's name */
      ReplaceChar(p[i].name,' ',SPACE_REPLACEMENT);

      /*Writes the structure into the text file*/
      fprintf(stream, "%s %d %f %s\n",p[i].name,p[i].age,
                                      p[i].salary,p[i].email);

      /*Brings the name string back to normal*/
      ReplaceChar(p[i].name,SPACE_REPLACEMENT,' ');
   }
}
/*
 * Description:
 *  Loads in the Person vector the contents of the text file
 * Parameters:
 *  p - a pointer to the Person vector
 *  numberOfPersons - how many elements the vector has
 *  stream - a pointer to the text file
 * Returns:
 *  Nothing
 */
void Persons_Load(Person *p, int *numberOfPersons, FILE* stream)
{
   char buffer[BUFFER_SIZE];
   char *result = NULL;
   while(feof(stream)==0)
   {
      /*Reads a line of the file*/
      result = fgets(buffer,BUFFER_SIZE,stream);
      /*Checks if the line reading was successful*/
      if(result!=NULL)
      {
         /*Interprets the line of the text and adds a new entry in the struct
           vector*/
         sscanf(buffer,"%s %d %f %s",p[(*numberOfPersons)].name,
                                     &p[(*numberOfPersons)].age,
                                     &p[(*numberOfPersons)].salary,
                                     p[(*numberOfPersons)].email);
         /*Replaces the SPACE_REPLACEMENT character with space*/
         ReplaceChar(p[(*numberOfPersons)].name,SPACE_REPLACEMENT,' ');
         /*Increments the Person counter*/
         (*numberOfPersons)++;
      }
    }
}

int main(void)
{
   Person persons[MAX_PERSONS] =
   {
      {"Clark Kent", 30, 3250.5, "superman@krypton.com"},
      {"Peter Griffin", 40, 1250.0, "birdmaster@familyguy.com"},
      {"Stewie Griffin", 3, 50000.0, "world_domination@familyguy.com"},
      {"Eric Cartman", 12, 50000.0, "autoritah@southpark.com"},
      {"Zapp Brannigan", 30, 200.5, "stargeneral@futurama.com"},
   };
   Person personsCopy[MAX_PERSONS];
   int numberOfPersons = 0;
   FILE* stream = NULL;

   /*Opens the stream into <write text> mode*/
   stream = fopen(PATH_TO_TXT_FILE,"wt");
   if(stream!=NULL)
   {
      /*Save the struct vector into the text file*/
      Persons_Save(&persons,5,stream);
      /*Closes the stream*/
      fclose(stream);
      /*Reopens the stream into <read text> mode*/
      stream = fopen(PATH_TO_TXT_FILE,"rt");
      if(stream!=NULL)
      {
         /*Loads the text file into another struct vector*/
         Persons_Load(&personsCopy, &numberOfPersons, stream);
         /*Closes the stream*/
         fclose(stream);
         /*Prints the results*/
         Persons_Print(&personsCopy,numberOfPersons);
      }
   }
   return 0;
}
A problem arises when you want to read from the text file a string that contains spaces because int sscanf ( const char * str, const char * format, ...) will not interpret it as a single string.

To solve this problem you can replace all space characters with a uncommon character for that string(in this example, I used '$' because is very uncommon when it comes to names).

Saturday, July 14, 2012

Text File I/O Operations in ANSI C

The ANSI C library stdio.h provides support for working with files and streams. To use a file, a pointer is necessary to make the connection between the physical file and the C I/O system.

1.Reading from a text file
int fgetc(FILE *stream)
Description
The function returns the next character of the stream as an unsigned char (converted to an int). It takes as parameters a pointer to the stream.
Returns
The read character from the stream or EOF if it encounters the end of file or if an error occurs.
Example
#include<stdio.h>

int main(void)
{
   FILE* f = NULL;
   char c;
   /*Opens the stream*/
   f = fopen("file.txt", "rt");
   if (f != NULL)
   {
      /*Reads the file character by character and
      prints the results*/
      do
      {
         c = fgetc(f);
         if (c != EOF)
         {
            putchar(c);
         }
      } while (c != EOF);
      fclose(f);
   }
   else
   {
      puts("Could not open file");
   }
   return 0;
}
The program above reads a text file and prints its content character by character.

char* fgets(char* string, int n,  FILE *stream)
Description
The function reads at most n-1 characters into the character array string, stopping if it encounters a newline character (which will be included in the array as well). A string terminator will be added to the array in the end ('\0').
Returns
The function returns a pointer to the character array if the operation was successful or NULL if an error was encountered.
Example
#include<stdio.h>

int main(void)
{
    const int BUFFER_SIZE = 200;
    FILE* f = NULL;
    char buffer[BUFFER_SIZE];
    /*Opens the stream*/
    f = fopen("file.txt","rt");
    if(f!=NULL)
    {
       /*Reads the file line by line until EOF is encountered*/
       while(feof(f)==0)
       {
          /*Reads a line*/
          fgets(buffer,BUFFER_SIZE,f);
          /*Prints the line*/
          puts(buffer);
       }
       fclose(f);
    }
    else
    {
       puts("Could not open file");
    }
    return 0;
}
int fscanf(FILE *stream, const char *format, ...)
Description
The function reads from the stream formatted data and assigns values to the subsequent arguments. It is very similar to int scanf(const char *format, ...) with the exception that you can specify the used stream. If you want to learn more, check the articles on console I/O and formatted strings.
Returns
The function returns the number of items who were converted and assigned. If it encounters the end of the file or if an error happens it will return EOF.
Example
We shall consider a file containing only integers which are separated by a space character:
#include<stdio.h>

int main(void)
{
   FILE* f = NULL;
   int number = 0;
   int status = 0;
   /*Opens the stream*/
   f = fopen("file.txt","rt");
   if(f!=NULL)
   {
      /*Reads every integer from the file and prints it*/
      while(feof(f)==0)
      {
         /*Tries to read an integer*/
         status = fscanf(f,"%d",&number);
         if(status!=EOF)
         {
            printf("%d ",number);
         }
         else
         {
            puts("Non-integer found");
         }
      }  
      fclose(f);
   }
   else
   {
      puts("Could not open file");
   }
   return 0;
}
2.Writing to a Text File
int fputc(int c, FILE *stream)

Description
The function writes the character c (represented as an integer) to the stream. It takes as parameters the character (c) and a pointer to the stream (stream).
Returns
The function returns the written character if the operation was successful. Otherwise it returns EOF.
Example
We shall consider a file containing only integers which are separated by a space character:
#include<stdio.h>
#include<string.h>

int main(void)
{
   FILE* f = NULL;
   int i;
   char sentence[] = "The bird is the word";
   int size, status;
   /*Opens the stream*/
   f = fopen("file.txt","wt");
   if(f!=NULL)
   {
      /*Computes the length of the character array*/
      size = strlen(sentence);
      /*Writes the character array character by character*/
      for(i = 0; i<size; i++)
      {
         status = fputc(sentence[i],f);
         if(status == EOF)
         {
            puts("Error occurred while writing the file");
         }
      }  
   }
   else
   {
      puts("Could not open file");
   }
   return 0;
}
int fputs(const char *s, FILE *stream)
Description
The function writes the string s to the stream stream. The string doesn't need to co
Returns
The function returns a non-negative number if the operation was successful. Otherwise it returns EOF.
Example
#include<stdio.h>

int main(void)
{
   FILE* f = NULL;
   char sentence1[] = "The bird is the word\n";
   char sentence2[] = "Bird! Bird! Bird!\n";
   /*Opens the stream*/
   f = fopen("file.txt","wt");
   if(f!=NULL)
   {
      /*Writes the first sentence*/
      fputs(sentence1,f);
      /*Writes the second sentence*/
      fputs(sentence2,f);
   }
   else
   {
      puts("Could not open file");
   }
   return 0;
}

int fprintf(FILE *stream, const char *format, ...)
Description
The function writes to the stream formatted data.  It is very similar to int printf(const char *format, ...), with the exceptions that you can specify the used stream. If you want to learn more, check the articles on console I/O and formatted strings.
Returns
The function returns the number of written characters if the operation was successful. Otherwise it returns a negative number.
#include<stdio.h>

#define NAME_SIZE 60

typedef struct
{
   char name[NAME_SIZE];
   int age;
}Person;

int main(void)
{
   FILE* f = NULL;
   Person john = {"John Doe", 30};

   /*Opens the stream*/
   f = fopen("file.txt","wt");
   if(f!=NULL)
   {
      /*Writes formatted text*/
      fprintf(f,"Name: %s | Age: %d",john.name, john.age);
   }
   else
   {
      puts("Could not open file");
   }
   return 0;
}

Creating, Removing and Renaming Files in ANSI C

The ANSI C library stdio.h provides support for working with files and streams. To use a file, a pointer is necessary to make the connection between the physical file and the C I/O system.

1.Creating a File

To create you can use FILE* fopen(char* fileName, char* mode) using the mode "wt". This will create a new file file at the specified filename. If you are not familiar with this function, read this.

Example:
#include<stdio.h>

int main(void)
{
   const int numberOfFiles = 10;

   FILE* f = NULL;
   char filename[FILENAME_MAX];
   int i = 0;

   /*Tries to create 10 files*/
   for(i = 0; i<numberOfFiles; i++)
   {   
       /*Dynamically creates the filename*/
       sprintf(filename,"MyFile%d.fil",i);
       /*Creates the file*/
       f = fopen(filename, "wt");
       /*Checks if the file was created successfully*/
       if(f!=NULL)
       { 
           printf("%s created successfully\n",filename);
           /*Closes the current stream*/
           fclose(f);
       }
       else
       {
           printf("%s could not be created\n",filename);
       }
   }
   return 0;
}
The program above will create 10 files in the current working directory called "MyFile0fil", "MyFile1.fil", ..., "MyFile9.fil"

2.Renaming a File

To rename a file, you must the function int rename(const char *oldname, const char *newname). The function takes as parameters the name of the existing file (oldname) and the new name of the file (newname). The function will return 0 if the operation was successful and a non-zero number if it failed.

Example:
#include<stdio.h>

int main(void)
{
   int status = rename("MyFile0.fil", "MyNewFile0.lif");
   if(status == 0)
   {
      puts("New file successfully renamed");
   }
   else
   {
      puts("Rename operation failed");
   }
   return 0;
}
The program above will take the file "MyFile0.fil" created in the precedent example and it will rename it to "MyNewFile0.lif".

3.Removing a File

To remove a file, you must use the function int remove(const char *filename). The function takes as parameters a string containing the path of the file which will be removed. It returns 0 if the operation was successful or a non-zero number if an error happened along the way.

Example:
#include<stdio.h>

int main(void)
{  
   int status = remove("MyNewFile0.lif");
   if(status == 0)
   {
      puts("File successfully removed");
   }
   else
   {
      puts("Remove operation failed");
   }
   return 0;
}
The program above will remove the file "MyNewFile0.lif" created in the precedent example.

Opening and Closing Streams in ANSI C

The ANSI C library stdio.h provides support for working with files and streams. To use a file, a pointer is necessary to make the connection between the physical file and the C I/O system.

1.Opening a stream
FILE* fopen(char* fileName, char* mode)
Description:
The function opens a stream to the named file (specified by its file name - char* fileName) in a specified mode (specified by char* mode).

The available modes are:
"rt"\"rb" Open file for reading
"wt"\"wb" Create file for writing. If any previous content exist, it shall be discarded
"at"\"ab" Opens or creates a file for writing, starting at the end of the file
"r+t"\"r+b" Open a file for update
"w+t"\"w+b" Creates text file for update. If any previous content exist, it shall be discarded
"a+t"\"a+b" Opens or creates a file for writing, starting at the end of the file

Files can be opened in text mode (example: "rt" opens a file for reading in text mode while "rb" opens a file for reading in binary mode).

The update mode (example "w+t") permits reading and writing on the same file. You must use int fflush(FILE* stream) or a file-positioning function between a read and a write to move the cursor at the position you want.
Returns:
The function returns a stream (FILE*) to the file if the call is successful. Otherwise returns NULL.
Tips&Tricks:
-The number of characters in a file name is limited by the FILENAME_MAX macro.
-The number of opened streams (files) is limited by the FOPEN_MAX macro.

2.Closing a Stream
int fclose(FILE* stream).
Description:
The function flushes any unwritten data for the stream sent as parameter, discards any unread buffered input and frees any automatically allocated buffer. After that it closes the stream.
Returns
0 - if the stream was successfully closed
EOF - if an error happened while closing the stream.

3.Example
#include<stdio.h>

int main(void)
{
   /*Variables*/
   FILE* f = NULL;
   int status = 0;

   /*Opens the stream*/
   f = fopen("file1.txt","rt");
   /*Checks if the stream was opened correctly*/
   if(NULL!=f)
   {
      puts("File was opened successfully");
      /*Closes the file*/
      status = fclose(f);
      /*Checks if the stream was closed correctly*/
      if(0==status)
      {
          puts("File closed successfully");
      }
      else
      {
          puts("File could not be closed");
      }
   }  
   else
   {
      puts("Could not access file");
   }
   return 0;
}


Tuesday, October 18, 2011

Text File I/O in Java

Reading from a Text File

To read information from a text file you will need to instantiate an object from the BufferedReader class. You will also need an InputStreamReader object and a FileInputStream, but those can be instantiated as anonymous objects.

In order to use this objects, you must import them from the java.io package.
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.IOException;
To "connect" to the text file, you will need to:
BufferedReader fin = new BufferedReader(new InputStreamReader
                                       (new FileInputStream("file.txt")));
At creation the BufferedReader class throws an IOException if the string (which contains the file's path) who serves as an argument for the anonymous FileInputStream object is invalid. So, you will need to place the statement above in a try-catch block.

Once created, the BufferedReader object (which I called fin) will be able to retrieve data from the text file. The easiest way to retrieve data is by reading the text file line by line:
String line;
String pathToFile = "file.txt"
BufferedReader fin = null; 
try
 {
    fin= new BufferedReader(new InputStreamReader
                            (new FileInputStream(pathToFile)));
    do
    {
      line = fin.readLine();
      if(line==null)        //Checks if you reached end of file
        break;               //Exits the loop if end of file reached
      //TO DO CODE
    }while(line!=null);
   fin.close();             //Close the stream
  }
catch(IOException e)
{
  System.out.println(e.getMessage() +"\nProgram will be aborted");
  System.exit(0);
}
It is very important to close the stream after you no longer need it. An opened stream that is no longer used can cause your program to have an erratic behavior sometimes.

The line which you read may contain numbers or other data types which you may want to load into your specific variables. To do that you will need to use StringTokenizer class. First, the class must be imported in your program:
import java.util.StringTokenizer;
To use the StringTokenizer, you will need to instantiate an object of this type. The constructor takes as arguments the string which you want to work with and a string which contains the delimiters. The delimiters represent the characters you use to separate your fields from one another in your text.
StringTokenizer strtok = new StringTokenizer(line," ");
Let's asume that you have a text file with the following structure: name age sex

Example:
Joe 32 M

If you want to assign the data from your text file to you program's variables, you can do it like this:
string name = strtok.nextToken().toString();
int age = Integer.parseInt(strtok.nextToken().toString()),
char sex = strtok.nextToken().toString().charAt(0);

Writing to a text file
To write data to a text file, you will need to instantiate an object of the PrintStream class. You will also need a FileOutputStream object to specify the file in which you want to write. If the file does not exist, it will be created by default. It is also required to place the entire operation in a try-catch block.

You will need to import the following classes:
import java.io.PrintStream;
import java.io.FileOutputStream;
import java.io.IOException
To "connect" to the text file:
PrintStream fout = new PrintStream(new FileOutputStream("file.txt"));
Once if you have access to the text file, you can simply write to it by using the PrintStream object:
fout.print("This is on line 1\n");
fout.print("This is on line 2\n");

Also, do not forget to close the output stream when you're done writing into your file.
fout.close();
Related Posts Plugin for WordPress, Blogger...