- Perl ›
- File input/output ›
- here
Read and write using random access
This is a random access example where you can pinpoint only the part you want to change, change it, and write it back. Random access is generally used for fixed-length binary files, but for convenience, we will use fixed-length text files here.
use strict; use warnings; # Used to use the option to specify the position of seek use Fcntl qw(:seek); # Rewrite the file contents by random access. my $file = "data_20080810.txt"; # Open in read/write mode (not very secure) open(my $fh, "+ <", $file) or die "Cannot open $file"; # 16 bytes my $len_rec = 16; # Beginning of record my $pos_name = 0; # Fixed length 8 bytes my $len_name = 8; # 8th byte from the beginning my $pos_age = 8; # Fixed length 8 bytes my $len_age = 8; # This time, add 1 to the age of peko. # peko is on the second record. Age is the 8th byte from the beginning of the record my $pos_peko_age = 1 * $len_rec + $pos_age; # Move the position of the file pointer to the position of Peco's age seek ($fh, $pos_peko_age, SEEK_SET) or die "Cannnot seek: $file:$!"; # Load peko's age into $age my $age; # Number of bytes read my $len_read; $len_read = read($fh, $age, $len_age); if (! defined $len_read) { die "Cannot read $file:$!"; } elsif ($len_read != $len_age) { die "Read only $len_read bytes"; } # Add 1 to age $age ++; # When read, the file pointer advances by the amount read, so return it to the original position. seek ($fh, $pos_peko_age, SEEK_SET) or die "Cannnot seek: $file:$!"; # Write to file printf $fh "%08s", $age or die "Cannot print: $file:$!"; # Close file close $fh or die "Cannot close $file:$!";
The following is the data to read. It is the data that three records (name 8 bytes, age 8 bytes) are lined up. Save it as data_20080810.txt.
taro 00000023peko 00000018akira 00000023
Code explanation
(1) Preparing to use the symbols used in the seek function
use Fcntl qw(:seek);
Import the symbols associated with the seek function from the Fcntl module. Three constants, SEEK_SET, SEEK_CUR and SEEK_END, are imported.
(2) How to specify the position in a fixed - length file
# 16 bytes my $len_rec = 16; # Beginning of record my $pos_name = 0; # Fixed length 8 bytes my $len_name = 8; # 8th byte from the beginning my $pos_age = 8; # Fixed length 8 bytes my $len_age = 8; # This time, add 1 to the age of peko. # peko is on the second record. Age is the 8th byte from the beginning of the record my $pos_peko_age = 1 * $len_rec + $pos_age;
For fixed-length files, you can specify the byte position directly. As mentioned above, it is convenient to define the length of one record, the position from the beginning of each data and the number of bytes, when specifying the position.
(3) Use the seek function to move to the byte position you want to read.
# Move the position of the file pointer to the position of Peco's age seek ($fh, $pos_peko_age, SEEK_SET) or die "Cannnot seek: $file:$!";
You can use the seek function to move the file pointer to the specified byte position. Think of a file pointer as a variable that remembers the byte position of the current file.
The first argument is the open filehandle, the second argument is the byte position you want to move, and the third argument is the reference position (start, current position, end).
The constants that can be specified for the third argument are as follows.
constant | meaning |
SEEK_SET | Based on the beginning of the file |
SEEK_CUR | Based on the position pointed to by the current file pointer |
SEEK_END | Based on the end of the file |
The value of the second argument is added based on the above position. SEEK_SET is used to specify the byte position from the beginning. In the case of SEEK_END, the second argument will specify a negative value.
If the seek function fails, it returns undef and sets $! To the error content.
(4) Read the data with the read function
# Load peko's age into $age my $age; # Number of bytes read my $len_read; $len_read = read($fh, $age, $len_age); if (! defined $len_read) { die "Cannot read $file:$!"; } elsif ($len_read != $len_age) { die "Read only $len_read bytes"; }
By using the read function, only the specified number of bytes can be read from the file. The first argument is the open filehandle, the second argument is the scalar variable that stores the read data, and the third argument is the number of bytes to read.
The return value of the read function is the number of bytes actually read. In case of read error, undef is returned and the error content is set in $!.
If the number of bytes read is insufficient, error handling is performed for each read error.
(5) Move to the write position with the seek function
# When read, the file pointer advances by the amount read, so return it to the original position. seek ($fh, $pos_peko_age, SEEK_SET) or die "Cannnot seek: $file:$!";
The read function advances the position of the file pointer by the amount read. To write to the same position again, call the seek function again.
(6) Write to a file
printf $fh "%08s", $age or die "Cannot print: $file:$!";
Writing is done by specifying the format with printf function. By specifying%08s, it means that "in an 8-digit string, the part less than 8 digits is filled with 0".