8

Given this code:

let any_offset: u64 = 42;
let mut file = File::open("/home/user/file").unwrap();
file.seek(SeekFrom::Start(any_offset));
// println!("{:?}", file.cursor_position()) 

How can I obtain the current cursor position?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
AndreyT
  • 1,449
  • 1
  • 15
  • 28
  • 4
    inspecting the result of `seek`. See the [docs for seek](https://doc.rust-lang.org/std/io/trait.Seek.html#tymethod.seek), `seek` returns a `Result`, where the u64 is the new position – Paolo Falabella Jan 19 '16 at 14:40
  • @PaoloFalabella: Shouldn't that be an answer? – Matthieu M. Jan 19 '16 at 18:59
  • It turns out that if I need it value later, then I should store it somehow, and manually update after each `seek` ? In my opinion it's stupid. – AndreyT Jan 19 '16 at 22:05
  • Or as alternative way: wrap File struct to my own and add needed functionality (i.e. create Proxy with position() method). But why I should do that, if it is the responsibility of File? – AndreyT Jan 19 '16 at 22:11

3 Answers3

12

You should call Seek:seek with a relative offset of 0. This has no side effect and returns the information you are looking for.

Seek is implemented for a number of types, including:

  • impl Seek for File
  • impl<'_> Seek for &'_ File
  • impl<'_, S: Seek + ?Sized> Seek for &'_ mut S
  • impl<R: Seek> Seek for BufReader<R>
  • impl<S: Seek + ?Sized> Seek for Box<S>
  • impl<T> Seek for Cursor<T> where
  • impl<W: Write + Seek> Seek for BufWriter<W>

Using the Cursor class mentioned by Aaronepower might be more efficient though, since you could avoid having to make an extra system call.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • So for a stream implementing `Seek` but not providing direct cursor access, the only way is `stream.seek(SeekFrom::Current(0)).unwrap()`. That's...verbose. – Kyle Strand Jan 16 '19 at 01:46
  • 6
    ...actually, there's a deeper problem: this requires mutably borrowing the stream. – Kyle Strand Jan 16 '19 at 01:49
  • Careful, if you're using a `BufWriter` this has the side affect of flushing to disk, even if the offset is just `0` like in this case. This can have a serious performance impact. – Todd Sewell Oct 26 '21 at 20:04
3

According to the Seek trait API the new position is returned with the seek function. However you can also take the data of the File, and place it within a Vec, and then wrap the Vec in a Cursor which does contain a method which gets the current position.

Without Cursor

let any_offset: u64 = 42;
let mut file = File::open("/home/user/file").unwrap();
let new_position = file.seek(SeekFrom::Start(any_offset)).unwrap();
println!("{:?}", new_position);

With Cursor

use std::io::Cursor;

let any_offset: u64 = 42;
let mut file = File::open("/home/user/file").unwrap();
let contents = Vec::new();
file.read_to_end(&mut contents);
let mut cursor = Cursor::new(contents);
cursor.seek(SeekFrom::Start(any_offset));
println!("{:?}", cursor.position());
XAMPPRocky
  • 3,160
  • 5
  • 25
  • 45
2

As of Rust 1.51.0 (2021) there is now the method stream_position() on the Seek trait.

use std::io::Seek;

let pos = file.stream_position().unwrap();

However, looking at the source code in the linked documentation this is purely a convenience wrapper that uses the same SeekFrom::Current(0) implementation behind the scenes.

JShorthouse
  • 1,450
  • 13
  • 28