从 io.ReadCloser 中提取文件名

问题描述

我需要获取从前端接收后端的某些文件文件名。后端(在 Go 中实现)将接收文件io.ReadCloser。有没有办法从 io.ReadCloser提取它?

解决方法

后端(在 Go 中实现)将接收文件为 io.ReadCloser。有没有办法从 io.ReadCloser 中提取它?

没有

通过运行 go doc io.ReadCloser 查看 io.ReadCloser 提供的方法,并注意没有提供名称的方法。因此,除非您对它是一个 io.ReadCloser 一无所知,否则您根本无法做到。

,
package main

import (
    "errors"
    "fmt"
    "io"
    "os"
)

func fatalln(err error) {
    fmt.Fprintln(os.Stderr,err)
    os.Exit(1)
}

// hasName interface is an interface that expects types
// that implements it to have "Name() string" method.
type hasName interface {
    Name() string
}

func open(name string) (io.ReadCloser,error) {
    f,err := os.Open(name)
    if err != nil {
        return nil,err
    }
    // f implements io.ReadCloser interface as *os.File
    // has Read and Close methods.
    return f,nil
}

func main() {
    // rc is of the type io.ReadCloser
    rc,err := open("example.txt")
    if err != nil {
        fatalln(err)
    }
    defer rc.Close()

    // Type assetion to check rc's underlying type has
    // a method "Name() string".
    f,ok := rc.(hasName)
    if !ok {
        fatalln(errors.New("type assertion failed"))
    }

    // Yay,type assertion succeeded. Print the name!
    fmt.Println("Name:",f.Name())
}
,

这里的 io.ReadCloser 是运行时读取器的读取器,它在前端将文件发送到后端时从网络读取文件。您必须根据请求本身来获取该文件名。 这是一个假设,但在大多数此类文件上传情况下,请求是多部分请求。如果你有同样的情况,你可以读取标题,通常是 Content-Disposition 来识别文件类型。 Go native http.Request 具有解析细节的能力。你可以试试这个:

formFile,handler,err := r.FormFile("file")  // read file from network with key "file"
defer formFile.Close()

fileName := handler.Filename // Get file name
,

通过定义一个嵌入 const options = { types: ['address'],componentRestrictions: {country: 'gb'},}; 的接口,您可以预先要求一个 io.Reader 方法:

Name()

这仅在传入的内容具有名称方法(例如 package main import ( "fmt" "io" "log" "os" ) type NamedReadCloser interface { io.ReadCloser Name() string } func doThings(f NamedReadCloser) error { defer f.Close() b,err := io.ReadAll(f) if err != nil { return err } fmt.Printf("Name: %s,Content: %s\n",f.Name(),b) return nil } func main() { f,err := os.Open("/etc/hosts") if err != nil { log.Fatal("Cannot open file: ",err) } err = doThings(f) if err != nil { log.Fatal("Error doing things: ",err) } } )时才有效。如果没有,那么您尝试做的事情是不可能的。

,

您必须使用 Name 方法将其强制转换为类型:

package main

import (
   "io"
   "os"
)

func open(name string) (io.ReadCloser,error) {
   return os.Open(name)
}

func main() {
   c,e := open("file.txt")
   if e != nil {
      panic(e)
   }
   defer c.Close()
   f := c.(*os.File)
   println(f.Name())
}