CIS 33A Perl handout week 10 part 2
Preliminary material should be here.
Sample programs from Clare Nguyen (edited by Ira Oldham)
############## random file access and $. ############
Lecture week 10 hour 2 Example Part 1
#########################
# Copy the contents of a specified file, with changed format
# Exactly one argument must be provided
# The argument is the name of the file to be read
# Each line in the file is a record
# Each record contains two fields, separated by :
# The first field is a Name
# The second field is Age
# Example:
# John Smith:93
# Each line will be changed in format
# The output file will contain:
# A minimum of 20 characters, left justified, for the name
# A space is written after the name.
# A minimum of 3 characters, filled with leading zeros, for
# the age
# A space is written after the age.
# No \n characters are written to "outfile"
# For the records in "outfile" to be usable, they must all
# be 25 characters long
# Thus every name in the input file MUST be
# 20 characters or less, and
# every age must be 3 characters, or less
# The output will be written to a file named "outfile"
# verify exactly one argument
1. die "Usage: $0 filename\n" if @ARGV != 1;
# Open specified input file, and open "outfile" for output
2. open (IN,"$ARGV[0]") || die "Cannot open $ARGV[0].\n";
3. open (OUT,">outfile") || die "Cannot open outfile.\n";
# Read a line, reformat it, and write it out
4. while (<IN>)
5. {
6. ($name, $age) = split /:/;
7. $str = sprintf ("%-20s %03d ", $name, $age);
8. print OUT $str;
9. }
# Note that "outfile" is written with NO \n characters
# print the position at the end of "outfile"
# Example: If there are 5 records, each 25 bytes long
# The final position will be 125 after reading 5 records,
# positioned ready to read a Byte following the last read
# The data is in positions 0 through 124
10. $pos = tell(OUT);
11. print "position is $pos\n";
# move back to the beginning
12. seek(OUT,0,0);
# should now print 0 Bytes from the beginning
13. $pos = tell(OUT);
14. print "position is $pos\n";
15. close (IN);
16. close (OUT);
#########################
Lecture week 10 hour 2 Example Part 2
#########################
# read and print the first and last records in "outfile" # "outfile" was created in Part 1 # If the input file met the required specifications, # each record in "outfile" contains exactly 25 characters, # with NO "\n" or other separator between records # Reopen "outfile" for reading 1. open (OUT,"outfile") || die "Cannot open outfile.\n"; 2. $rec_length = 25; # start at the beginning ( default anyway ) 3. seek (OUT, 0, 0); # read and print the first record, which has length 25 Bytes 4. read(OUT, $rec, $rec_length); 5. print "first record is $rec\n"; # seek to 25 Bytes from the end of the file 6. seek (OUT, -$rec_length, 2); # 2 means end # print the position of the beginning of the last record 7. $pos = tell(OUT); 8. print "position is $pos\n"; # read and print the last record 9. read(OUT, $rec, $rec_length); 10. print "last record is $rec\n"; 11. close (OUT);
#########################
Lecture week 10 hour 2 Example Part 3
#########################
# seek, read, and print record 4
# seek and write a new record at the end
# seek, read, and print record 3
# NOTE that there is always a seek or tell between
# read and write, or write and read
# open "outfile" for reading and writing
1. open (OUT,"+<outfile") || die "Cannot open outfile.\n";
2. $rec_length = 25;
# seek to the beginning of the 4th record
# print the position
# read and print the 4th record
3. seek (OUT, 3*$rec_length, 0);
4. $pos = tell(OUT); # save position of record 4
5. print "position is $pos\n";
6. read (OUT, $rec, $rec_length);
7. print "fourth record is $rec\n";
# seek to the end
# get data for a new record from the user
# add the new record at the end
# NOT done here:
# The new name and age should be checked for length
# If you write a record that is not the right length
# it will make a mess of the seek activities
8. seek (OUT, 0, 2);
9. print "enter name: ";
10. chomp ($name = <STDIN>);
11. print "enter age: ";
12. chomp ($age = <STDIN>>);
13. $str = sprintf ("%-20s %03d ",$name, $age);
14. print OUT $str;
# seek to record 3 (the location saved in $pos is record 4)
# read and print record 3
15. seek (OUT, $pos - $rec_length, 0);
16. $pos = tell(OUT);
17. print "position is $pos\n";
18. read (OUT, $rec, $rec_length);
19. print "third record is $rec\n";
20. close OUT;
#########################
Lecture week 10 hour 2 Example Part 4
#########################
# Now create a new file, NOT used in parts 1, 2 and 3
# open "fileOut" to write and read
1. open (F,"+>fileOut") || die "Cannot open outFile.\n";
# Request user enter name and age per line
# with no spaces in the name
# with space between the name and age
# User stops with <Ctrl-D>
# write the data into "fileOut" in the same format that
# we have been using for "outfile", except with \n
2. print "Enter name and age pair per line (^D to end): ";
3. while (chomp ($in = <STDIN>))
4. {
5. ($name, $age) = split(/\s+/,$in);
6. $str = sprintf("%-20s %03d\n", $name, $age);
7. print F $str; # write to "fileOut"
8. }
# seek back to the beginning
# print the first record
9. seek (F, 0, 0);
10. $rec = <F>; # this works because there are \n
# Without \n, read must be used
# to read 25 Bytes
11. print "first record is $rec\n";
# seek and print the last record
12. seek (F, -length($rec), 2);
13. $rec = <F>;
14. print "last record is $rec\n";
15. close F;
#########################
Lecture week 10 hour 2 Example Part 5
#########################
# open "fileA" for output and write 4 characters
# the pointer is now 4, ready to write Byte 5
1. open (F,">fileA") or die "Cannot open fileA\n";
2. print F "1\n2\n";
# Use the same file handle
# "fileA" is automatically closed
# open "fileB" for output and write 6 characters
# the pointer is now 6, ready to write Byte 7
3. open (F,">fileB") or die "Cannot open fileB\n";
4. print F "1\n2\n3\n";
5. close F;
# glob will generate names: fileA fileB
6. foreach $file (glob "file[AB]")
7. {
8. open (F,"$file") or die "Cannot open $file\n";
9. print "$.\n" while <F>; # print all line numbers
10. }
11. close F;
# again, the same file handle is used for both files
# fileA is automatically closed when the file handle is
# reused
# but, the line count is NOT reset
# prints
# 1
# 2
# 3
# 4
# 5
# corresponding to the 2 lines in fileA and 3 lines in fileB