读取刚刚写入临时文件的数据

问题描述

在Go中,我试图将数据写入到临时文件中,然后我转过身来读取并没有成功。以下是简化的测试程序。我已经通过检查临时文件验证了数据已写入文件中。因此,至少我知道数据正在将其写入文件。那只是我无法读出来。

谢谢您的帮助

package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
)

func main() {

    tmpFile,err := ioutil.TempFile("",fmt.Sprintf("%s-",filepath.Base(os.Args[0])))
    if err != nil {
        log.Fatal("Could not create temporary file",err)
    }
    fmt.Println("Created temp file: ",tmpFile.Name())
    //  defer os.Remove(tmpFile.Name())

    fmt.Println("Writing some data to the temp file")
    if _,err = tmpFile.WriteString("test data"); err != nil {
        log.Fatal("Unable to write to temporary file",err)
    } else {
        fmt.Println("data should have been written")
    }

    fmt.Println("Trying to read the temp file now")
    s := bufio.NewScanner(tmpFile)
    for s.Scan() {
        fmt.Println(s.Text())
    }
    err = s.Err()
    if err != nil {
        log.Fatal("error reading temp file",err)
    }
}

解决方法

ioutil.TempFile创建一个临时文件并打开该文件以进行读取和写入,并返回结果*os.File(文件描述符)。因此,当您在文件内部写入数据时,指针将移动到该偏移量,即当前位于文件末尾。 但是,当从文件中读取您的要求时,您需要使用Seek方法将*os.File.Seek返回到开头或任何需要的偏移量。因此,添加tmpFile.Seek(0,0)将为您提供所需的行为。

此外,作为一种好的做法,请不要忘记关闭文件。请注意,我使用了defer tmpFile.Close(),该文件在退出前会关闭文件。

请参考以下示例:

package main

import (
    "bufio"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
)

func main() {
    tmpFile,err := ioutil.TempFile("",fmt.Sprintf("%s-",filepath.Base(os.Args[0])))
    if err != nil {
        log.Fatal("Could not create temporary file",err)
    }
    defer tmpFile.Close()

    fmt.Println("Created temp file: ",tmpFile.Name())

    fmt.Println("Writing some data to the temp file")
    if _,err = tmpFile.WriteString("test data"); err != nil {
        log.Fatal("Unable to write to temporary file",err)
    } else {
        fmt.Println("Data should have been written")
    }

    fmt.Println("Trying to read the temp file now")

    // Seek the pointer to the beginning
    tmpFile.Seek(0,0)
    s := bufio.NewScanner(tmpFile)
    for s.Scan() {
        fmt.Println(s.Text())
    }
    if err = s.Err(); err != nil {
        log.Fatal("error reading temp file",err)
    }
}

更新: OP的评论:

考虑到删除实际文件是否也被推迟,是否需要推迟关闭?如果是这样,我想推迟的顺序会很重要。

所以,这是一个很好的问题。因此,基本的经验法则是关闭文件然后删除。因此,甚至有可能先删除它,然后再将其关闭,但这取决于操作系统。

如果您引用C++'s doc

如果当前正在由当前进程或其他进程打开文件,则此功能的行为由实现定义(特别是POSIX系统取消链接文件名,尽管即使最后一个文件系统空间也没有被回收)硬链接到文件,直到最后一个运行的进程关闭该文件,Windows不允许删除该文件)

因此,在Windows上,如果您尝试先删除它而不关闭它,那肯定是个问题。

因此,由于defer的堆积,执行顺序将是

defer os.Remove(tmpFile.Name()) // Called 2nd
defer tmpFile.Close() // Called 1st
,
package main

import (
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    content,err := ioutil.ReadFile("testdata/hello")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("File contents: %s",content)

根据官方的golang文档。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...