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,095
- 2
- 11
- 29
-
It depends on the underlying type. The `io.ReadCloser` interface in itself doesn't describe this information. Steven Penny's answer shows an example. – Hymns For Disco Jun 16 '21 at 02:09
-
It shows as a `*runtime.File`, can't cast to to `*os.File`. – Govinda Malavipathirana Jun 16 '21 at 03:04
5 Answers
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.

- 40,468
- 7
- 81
- 87
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,802
- 2
- 18
- 29
-
But as explained by @Volker in his answer that unless you know nothing more than it is an `io.ReadCloser`, you simply can't. So, take care of that. My answer just explores one way, there could be plenty of ways of doing it — I expect the underlying type should have a method named "Name" it might happen that the underlying type has a field that has the filename. – shmsr Jun 16 '21 at 05:58
-
While I would argue it is possible for a struct that implement a `Name` method and `io.ReadCloser`'s `Name` method to have nothing to do with filename (or even has any meaning outside of its internal use), this is actually a reasonably balanced try; however, I think it would be better if there is some error detecting mechanisms, but those would require more domain logic. – leaf bebop Jun 16 '21 at 09:18
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

- 1,129
- 9
- 17
-
error should be handled before using handler here. Otherwise there can be `panic - nil pointer dereference` . – nipuna Jun 16 '21 at 04:40
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.

- 989
- 8
- 21
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())
}