CMPS 335 Advanced Web Publishing Perl and CGI Programming


Reading and Writing Data Files


In running a Perl script, we can retrieve (input) data from or write (output) data to an external file stored on the server.   A data file has a regular file name, but it is referenced in a script through a label called filehandle.  The file handle is a handy way to refer to the file.  The open statement opens a file and initialize the file handle.  You perform all of the file operations on this handle until the file is closed.  File handles are usually spelled using all uppercase letters to distinguish the filehandle from Perl's reserved words, which are all lowercase.  STDIN is a predefined filehandle representing a script's normal input, which is the keyboard by default.  STDOUT is a predefined filehandle representing the screen by default.

The external data file discussed here is called a flat-file database.  Flat-file databases are typically ASCII text files containing one record of information per line.  The line termination serves as the record delimiter.

CGI scripts can get data from a form and generate data to the browser.  They can also reads data from or write data into a file.  When we run a CGI script, it is run with the world-executable permissions.  In order to write to a data file, we must make it world-writable.


Opening a File
Before you can read from or write to a file, you have to open the file with the following file opening statement:
         open(FILEHANDLE, "filename");

The filehandle is associated with the filename when the file is opened.  The filename may be prefixed with one of the following open operators.  The default open mode is read-only.
     operator  operation
     --------  -----------------------------------------
      <        Input (Read)
      >        Output (starting at the beginning of the
                   file and overwrite any existing data)
      >>       Output (write to end of existing file)

  Examples: 
    open(INF,"records.dat");
    open(OUTF,">>records.dat");          

Because a file opening operation can fail, an error function may be used with the system error message variable $!.  The $! variable contains the last system error message and is useful for determining the failure condition as shown in the following example (counter1.cgi):
     :
    open(INFILE, "countts.dat") or errorMessage();
     :
     :
    sub errorMessage {
        print "File could not be opened: $!");
        exit;
    } 

Locking a File
Several visitors may try to open and write to the same data file at the same time.  To get exclusive access to the file and to prevent possible file damage, use the following file locking function:

         flock(FILEHANDLE, 2);

where 2 is the file locking mode for exclusive lock.  The lock is released when the script finishes running, allowing the next CGI to access the file.  You should also reset the file pointer using the seek function.


Positioning with the SEEK Function
Normally, when you open a file for reading, the file handle is positioned at the start of the file.  The following seek function allows the file pointer to be moved forward and backward throughout the file.

         seek(FILEHANDLE, offset, whence);

where offset is the number of lines to move the pointer, relative to whence, which can be one of the three values:
     0   beginning of the file 
     1   current location
     2   end of the file      

  Examples: 
    seek(INFILE, 0, 0);    # Rewind the file to the beginning 
    seek(INFILE, -10, 2);  # The pointer is moved backward 

Closing a File
When you are finished reading or wrting a file, close the file using the close function as shown below: Files are also automatically closed when the execution of a script ends.


Reading a File
Of the multiple ways to read data from a file, the file input operator < > is the most straightforward.  The input operator reads the contents of a file in two different ways: reading one line at a time into a scalar variable or reading the entire file into an array as shown below:
   $scalar = <FILEHANDLE>;  # Read one line into a scalar variable
   @array = <FILEHANDLE>;   # Read the entire file into an array
A more flexible way to read data from a file is to use the read function to read a fixed amount of data using the following syntax: where buffer is a scalar variable to read the data into, length is the number of bytes or characters to read, and offset is the distance from the beginning of the buffer where the input is to go.  The offset is optional.
  Examples:
     read(STDIN, $studentName, 20);
     read(INFILE, $buffer, 255); 

Writing to a File
The print function can be used to save data to a file or to display data on screen using the following forms: The default filehandle is STDOUT, which is to your computer monitor (screen).


File I/O Examples
  Example 1 (standardIO.cgi)

  [jhu@cs cgi-bin]$ cat standardIO.cgi
  #!/usr/bin/perl
  # STDIN and STDOUT are default file handles opened at startup.
  # STDIN is normally set to the computer keyboard
  # STDOUT is normally set to the computer monitor
  print STDOUT "Enter the first number a: ";
  $a = ;
  print "Enter the second number b: ";
  $b = ;
  $c = $a + $b;
  print "Sum is $c \n";
  # End standardIO.cgi

  [jhu@cs cgi-bin]$ perl standardIO.cgi
  Enter the first number a: 7
  Enter the second number b: 5
  Sum is 12

  Example 2 (counter.cgi)

  [jhu@cs cgi-bin]$ cat counter.cgi
  #!/usr/bin/perl
  open(INFILE, "counts.dat") || &errorMessage; 
  flock(INFILE,2);
  seek(INFILE,0,0);
  $count = <INFILE>;
  close(INFILE);

  $count = $count +1;

  open(OUTFILE,">counts.dat");
  flock(OUTFILE,2);
  seek(OUTFILE,0,0);
  print OUTFILE "$count";
  close(OUTFILE);

  print "Content-type:text/html\n\n";
  print "  Visitor count:   $count.\n\n";

  sub errorMessage{
    print "Content-type:text/html\n\n";
    print "The server can't open the data file.\n";
    print "Either the permissions are wrong or the file doesn't exist.\n";
    exit;
  }

  [jhu@cs cgi-bin]$


  B. Data File (counts.dat)
    Create this file with the initial value 0 on the first and only line 
    of the file.  Make the file world-writable (permissions 666).

  [jhu@cs cgi-bin]$ cat counts.dat
  10
  [jhu@cs cgi-bin]$ chmod 666 counts.dat


  C. Running the script counter.cgi in the Unix command shell

  [jhu@cs cgi-bin]$ perl counter.cgi
  Content-type:text/html

   Visitor count:   11.


  D. Running the script counter.cgi in the browser's window
    (The following output appears in the browser's window)

  Visitor count: 12. 

 
  E. The Server-Side Include Statement
     Add the following SSI statement to the HTML page you want counted 
     and at wherever the result is to be displayed.

     <!--#exec cgi= "cgi-bin/counter.cgi"-->
 
     (Note: The HTML document that contains the SSI should have 755 
        permissions and the .shtml extension to be server parsed)
Return to CMPS 335 Home Page
Return to Web Site Home Page