创建文件和读取文件之间的竞态条件

huangapple go评论71阅读模式
英文:

Race condition between creating file and ioutil.ReadFile

问题

我有一个使用golang编写的Web应用程序端点,允许上传图像,但我发现使用ioutil.ReadFile创建文件并立即读取它会导致data为空。但是,如果稍后再次调用它,data将包含数据。

r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("my_input_name")

f, err := os.OpenFile("./img_dump/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
   return
}
// 第一次调用时,data为空[]
data, err := ioutil.ReadFile("/myAbsolutePath/img_dump/" + handler.Filename)
// 这样不起作用,data为空
fmt.Println(len(data))

f.Sync()

data, err = ioutil.ReadFile("/myAbsolutePath/img_dump/" + handler.Filename)

// 这样不起作用,data为空
fmt.Println(len(data))

c1 := make(chan string, 1)
go func() {
    time.Sleep(time.Second * 5)
    c1 <- "result 1"
}()

go func(name string) {
    select {
    case _ = <-c1:
        data, err = ioutil.ReadFile("/myAbsolutePath/img_dump/" + name)
        fmt.Println("after sleep")
        // 只有在不尝试f.Close()时才起作用,data不为空
        fmt.Println(len(data))
    }
}(handler.Filename)

有没有办法避免创建和读取之间的竞争条件,也许使用promise?

编辑:我尝试使用Sync刷新文件,但问题仍然存在。

英文:

I have a golang web app end point that allows uploading image, but I find that creating a file and immediately reading it using ioutil.ReadFile will result in data to be empty. But if I call it again in some time later it will contain the data.

    r.ParseMultipartForm(32 &lt;&lt; 20)
    file, handler, err := r.FormFile(&quot;my_input_name&quot;)

    f, err := os.OpenFile(&quot;./img_dump/&quot;+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
       return
    }
    // data is empty [] when first called
    data, err := ioutil.ReadFile(&quot;/myAbsolutePath/img_dump/&quot;  + handler.Filename)
    // This does not work, data is empty
    fmt.Println(len(data))

    f.Sync()

    data, err = ioutil.ReadFile(&quot;/myAbsolutePath/img_dump/&quot;  + handler.Filename)

    // This does not work, data is empty
    fmt.Println(len(data))

    c1 := make(chan string, 1)
    go func() {
        time.Sleep(time.Second * 5)
        c1 &lt;- &quot;result 1&quot;
    }()

    go func(name string) {
        select {
        case _ = &lt;-c1:
            data, err = ioutil.ReadFile(&quot;/myAbsolutePath/img_dump/&quot; + name)
            fmt.Println(&quot;after sleep&quot;)
            // This only works if I don&#39;t try f.Close(), data is not empty
            fmt.Println(len(data))
        }
    }(handler.Filename)

Is there a way to avoid race condition between creating and reading, maybe a promise?

Edit: I tried Sync to flush file but same issue still exist.

答案1

得分: 1

你尝试过使用File.Sync吗?

> Sync将文件的当前内容提交到稳定存储中。
> 通常,这意味着将文件系统中最近写入的数据刷新到磁盘上的内存副本。

附加参考资料

f, err := os.OpenFile("./img_dump/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {...}

err = f.Sync()
if err != nil {...}

err = f.Close()
if err != nil {...}

data, err := ioutil.ReadFile("/myAbsolutePath/img_dump/"  + handler.Filename)
英文:

Have you tried using File.Sync ?

> Sync commits the current contents of the file to stable storage.
> Typically, this means flushing the file system's in-memory copy of
> recently written data to disk.

Additional Reference

f, err := os.OpenFile(&quot;./img_dump/&quot;+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {...}

err = f.Sync()
if err != nil {...}

err = f.Close()
if err != nil {...}

data, err := ioutil.ReadFile(&quot;/myAbsolutePath/img_dump/&quot;  + handler.Filename)

huangapple
  • 本文由 发表于 2017年7月24日 13:55:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/45273503.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定