When you open() a file you create an entry in the system file table and you get an fd that points to that file table entry. The file table entry has an integer called the file pointer that indicates the next byte to be read or wriitten in the file. As you read the file, the file pointer gets updated.
When you duplicate an fd by any means such as dup(), fcntrl(), or even fork(), you get new fd's that point to the same file table entry.
If you want two file pointers to the same file, you must have two file table entries in which to store them. That means two open() calls.