For some file systems like ext4 or btrfs on Linux, you can use filefrag to get the offsets of the data segments for the file on the block device the file system is on.
$ seq 1000 > a
$ filefrag -v a
Filesystem type is: ef53
File size of a is 3893 (1 block of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 0: 82784147.. 82784147: 1: eof
a: 1 extent found
$ sudo dd bs=4k skip=82784147 count=1 if=/dev/storage/home 2>&- | head
1
2
3
4
5
6
7
8
9
10
Here the block device is a LVM volume. That volume may have physical volumes on disks, on partitions, on RAID arrays, on files, on RAM, on network block devices... Going back to an actual disk or set of disk may prove difficult.
In my case, it's relatively easy, as it's just a logical volume on top of one GPT partition as one linear stretch.
$ sudo dmsetup table /dev/storage/home
0 1953120256 linear 8:98 384
So /dev/storage/home is 384 sectors within device 8:98, which happens to be /dev/sdg2
for me.
$ cat /sys/block/sdg/sdg2/start
489060352
So sdg2 is 489060352 sectors within /dev/sdg (the 7th disk on this system).
So I can obtain the offset within the single disk that file is on with:
$ sudo dd if=/dev/sdg skip="$((489060352+384+82784147*8))" count=1 2> /dev/null | head
1
2
3
4
5
6
7
8
9
10