问题描述
我需要获取从前端接收后端的某些文件的文件名。后端(在 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())
}