从io.ReadCloser中提取文件名

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

Extract filename from io.ReadCloser

问题

我需要获取从前端传递给后端的某个文件的文件名。后端(使用Go语言实现)将以io.ReadCloser形式接收文件。有没有办法从io.ReadCloser中提取文件名?

英文:

I need to get the filename of certain file(s) that receives backend from the frontend. Backend (implemented in Go) will receive the file as io.ReadCloser. Is there way I could extract it from the io.ReadCloser?

答案1

得分: 4

后端(使用Go实现)将以io.ReadCloser形式接收文件。有没有办法从io.ReadCloser中提取文件?

没有。

运行go doc io.ReadCloser查看io.ReadCloser提供的方法,并注意没有提供提取文件名的方法。所以,除非你只知道它是一个io.ReadCloser,否则你无法提取文件名。

英文:

> Backend (implemented in Go) will receive the file as io.ReadCloser. Is there way I could extract it from the io.ReadCloser?

No.

Take a look at which methods an io.ReadCloser provides by running go doc io.ReadCloser and note that there isn't a method which will provide a name. So unless you know nothing more that that it is an io.ReadCloser you simply cannot do it.

答案2

得分: 1

package main

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

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

// hasName接口是一个期望实现它的类型具有"Name() string"方法的接口。
type hasName interface {
	Name() string
}

func open(name string) (io.ReadCloser, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	// f作为*os.File实现了io.ReadCloser接口,具有Read和Close方法。
	return f, nil
}

func main() {
	// rc的类型是io.ReadCloser
	rc, err := open("example.txt")
	if err != nil {
		fatalln(err)
	}
	defer rc.Close()

	// 类型断言来检查rc的底层类型是否具有"Name() string"方法。
	f, ok := rc.(hasName)
	if !ok {
		fatalln(errors.New("类型断言失败"))
	}

	// 哇,类型断言成功。打印名称!
	fmt.Println("名称:", f.Name())
}

以上是给定的Go代码的翻译。

英文:
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())
}

答案3

得分: 0

这里的io.ReadCloser是一个运行时读取器,用于从网络中读取文件,前端将文件发送到后端。您需要在请求本身上进行处理,以获取该文件名。
这是一个假设,但在大多数文件上传的情况下,请求是一个多部分请求。如果您遇到相同的情况,您可以读取头部,通常是Content-Disposition,以识别文件类型。Go的原生http.Request具有解析细节的能力。您可以尝试以下代码:

formFile, handler, err := r.FormFile("file")  // 使用键名"file"从网络中读取文件
defer formFile.Close()

fileName := handler.Filename // 获取文件名
英文:

The io.ReadCloser here is a reader for runtime reader which reads file from network as the frontend sends it to backend. You'll have to work on request itself to get that file name.
This is an assumption but in most such cases for file upload, the request is a multipart request. If you have the same situation, you can read the headers, typically Content-Disposition to identify the file type. Go native http.Request has ability to parse the details. You can try this :

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

fileName := handler.Filename // Get file name

答案4

得分: 0

通过定义一个嵌入了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)
	}
}

只有当传入的内容具有一个名字方法,比如*os.File时,这个方法才会起作用。如果没有,那么你想要做的是不可能的。

英文:

By defining an interface which embeds io.Reader you can require a Name() method up front:

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)
	}
}

This will only work if what is passed in has a name method, like an *os.File. If it does not, then what you are trying to do is not possible.

答案5

得分: -1

你需要将其转换为具有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())
}
英文:

You'll have to cast it to a type with a Name method:

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())
}

huangapple
  • 本文由 发表于 2021年6月16日 09:58:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/67995440.html
匿名

发表评论

匿名网友

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

确定