6

This problem was solved. Thank you very much.
My question and the solution I am using is stated below.

Question:

open IN, "<./test.txt";
seek(IN,10,0);
read IN, $temp, 5;

seek(IN,20,0);
close(IN);


The situation is that, my handle will start at position 0.
After the first seek function, my file handle will at position 10.
After I read, my handle will at position 15.
At this moment, I seek again. Then the program will seek from the beginning or from position 20.
My question is that is there anyway for me to do searching in a file so that I do not need to search from the starting point of the file every time?


The way I am using:

use Fcntl qw(SEEK_SET SEEK_CUR SEEK_END); #SEEK_SET=0 SEEK_CUR=1 ...

$target_byte=30;
open IN, "<./test.txt";
seek(IN,10,SEEK_SET);
read IN, $temp, 5;

$position=tell(IN);
seek(IN,$target_byte-$position,SEEK_CUR);
#do what I want
close(IN);
sflee
  • 1,659
  • 5
  • 32
  • 63
  • `$position=tell(IN); seek(IN,$target_byte-$position,SEEK_CUR);` is a weird way of doing `seek(IN,$target_byte,SEEK_SET);` – ikegami Jan 09 '19 at 03:14

1 Answers1

29

Before we start,

  • The assumption you ask us to make no sense. The first byte is at position zero. Always.

  • It's called a "file handle" (since it allows you to hold onto a file), not a "file handler" (since it doesn't handle anything).

It would be clearer if you used the constants SEEK_SET, SEEK_CUR and SEEK_END instead of 0, 1 and 2.

Your code is then

use Fcntl qw( SEEK_SET );

open IN, "<./test.txt";
seek(IN,10,SEEK_SET);
read IN, $temp, 5;

seek(IN,20,SEEK_SET);
close(IN);

As the name implies, it sets the position to the specified value.

So,

  • After the first seek, the file position will be 10.
  • After the read, the file position will be 15.
  • After the second seek, the file position will be 20.

Visually,

         +--------------------------  0: Initially.
         |         +---------------- 10: After seek($fh, 10, SEEK_SET).
         |         |    +----------- 15: After reading "KLMNO".
         |         |    |    +------ 20: After seek($fh, 20, SEEK_SET).
         |         |    |    |
         v         v    v    v     
file:    ABCDEFGHIJKLMNOPQRSTUVWXYZ
indexes: 01234567890123456789012345

If you wanted to seek relative to your current position, you'd use SEEK_CUR.

         +--------------------------  0: Initially.
         |         +---------------- 10: After seek($fh, 10, SEEK_CUR).
         |         |    +----------- 15: After reading "KLMNO".
         |         |    |         +- 25: After seek($fh, 10, SEEK_CUR).
         |         |    |         |
         v         v    v         v 
file:    ABCDEFGHIJKLMNOPQRSTUVWXYZ
indexes: 01234567890123456789012345
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • `use Fcntl qw(:seek);` is not in the seek docs. It is not required and I don't accept that extra, un-rememberable lines of code and symbols are good, even if they are more orderly in your opinion. That's what your downvote is for. – felwithe Mar 30 '21 at 23:04
  • The reason you gave is exactly the reason to use the appropriate constants. Having to memorize unrememberable magical numbers if a recipe for errors. And those constants *are* documented in the `seek` docs. Specifically, the docs for the system call to which the numbere are passed. In fact, whatever numbers correspond to those constants is not even mentioned in those docs. This raises the question as to whether the magic numbers mentioned in Perl's docs are even always correct! – ikegami Mar 31 '21 at 02:31