You do not need to use buffered I/O for this task.
The *os.File type implements both the io.Seeker and io.Reader (or
io.ReadSeeker, which embeds both) interfaces, so basically your
approach should be like this:
1. Settle on a buffer size, say, 8 KiB or whatever.
Let this value be named bufSuze.
2. Get the file length calling Stat() on *os.File;
3. Subtract bufSize bytes from the file's size (or take its full
size if it's less than bufSize), save this number, Seek() to that
position, read bufSize bytes into a byte slice of the length bufSize
using the Read() method.
Note that the actual amount of data read might be less than
bufSize as the file might shrink during reading.
Seek() might fail due to the same reason.
4. Scan the bytes in the buffer backwards, looking for the terminating
character.
5. If not found, subtract bufSize from the position saved on step (3),
Seek(), Read(), go to step (4).