How to get an exclusive lock on a file in go
Asked Answered
N

2

25

How can I get an exclusive read access to a file in go? I have tried documentations from docs but I am still able to open the file in notepad and edit it. I want to deny any other process to have access to read and write while the first process has not closed it explicitly. In .NET I could do something as:

File.Open("a.txt", FileMode.Open, FileAccess.ReadWrite, FileShare.None);

How do I do it in go?

Nelrsa answered 25/10, 2018 at 9:55 Comment(2)
Such a feature depends on the file system in use and cannot be guaranteed by Go.Aforementioned
There is no "Microsoft" tag but this question is specifically aimed at using Go on Microsoft operating systemsGynandry
N
20

I finally found a go package that can lock a file.

Here is the repo: https://github.com/juju/fslock

go get -u github.com/juju/fslock

this package does exactly what it says

fslock provides a cross-process mutex based on file locks that works on windows and *nix platforms. fslock relies on LockFileEx on Windows and flock on *nix systems. The timeout feature uses overlapped IO on Windows, but on *nix platforms, timing out requires the use of a goroutine that will run until the lock is acquired, regardless of timeout. If you need to avoid this use of goroutines, poll TryLock in a loop.

To use this package, first, create a new lock for the lockfile

func New(filename string) *Lock

This API will create the lockfile if it already doesn't exist.

Then we can use the lockhandle to lock (or try lock) the file

func (l *Lock) Lock() error

There is also a timeout version of the above function that will try to get the lock of the file until timeout

func (l *Lock) LockWithTimeout(timeout time.Duration) error

Finally, if you are done, release the acquired lock by

func (l *Lock) Unlock() error

Very basic implementation

package main

import (
    "time"
    "fmt"
    "github.com/juju/fslock"
)

func main() {
    lock := fslock.New("../lock.txt")
    lockErr := lock.TryLock()
    if lockErr != nil {
        fmt.Println("falied to acquire lock > " + lockErr.Error())
        return
    }

    fmt.Println("got the lock")
    time.Sleep(1 * time.Minute)

    // release the lock
    lock.Unlock()
}
Nelrsa answered 26/10, 2018 at 12:0 Comment(10)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewAdvertisement
Please don't delete this answer. This is written for someone who might need to do this/similar stuff in future. I have spent a lot of hrs to search this packageNelrsa
your package uses flock() for locking on Unix so doesn't provide OS level mandatory lockingGynandry
we were only looking for windowsNelrsa
this package is GPL licensed, so can't be used for commercial products. Any other package that you have come across?Apparitor
@AmitBhaira It is LGPLv3 which allows for use in commercial products. See choosealicense.com/licenses/lgpl-3.0Ternion
GPL also allows commercial use! It just needs you to distribute the whole program using the GPL code under GPL itself when publishing. With LGPL, you need to publish changes to the library under LGPL (or compatible) again when releasing the program.April
I see this package problematic because there hasn't been any modification to the code since 2016. If the author was Donald Knuth I'd say this is okay but apparently the Go community has some thoughts on it as well: go.googlesource.com/proposal/+/master/design/…Scission
@KonradKleine Man you're a life saver. We've been having issues with "github.com/nightlyone/lockfile" and I'm not sure if the library is bugged or I screwed up. It's not clear what guarantees that library makes and the other couple libraries also leave me feeling a little uneasy. Glad the Go team has an official thread on it. :)Introduce
Using LGPL licensed libraries in commercial closed-sourced golang projects doesn't really work, see here. There is an alternative to this library that is BSD-3 licensed: github.com/gofrs/flockErato
B
0

Right now I would recommend go-internal

go get github.com/rogpeppe/go-internal

The reason is, Go does have a lock package but it's internal (we can't use) and go-internal is just providing us the same code as a package.

Also, it uses os.File instead of creating another struct. So it's probably very compatible with others Go codes.

package main

import (
    "fmt"

    "github.com/rogpeppe/go-internal/lockedfile"
)

func main() {
    file, _ := lockedfile.Edit("example.txt") // Write Lock
    fmt.Fprintf(file, "%d", 10)
    file.Close() // Unlock
}

Negative side, doesn't have "try lock" or timeout.

Bentonbentonite answered 1/8 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.