В стандартной библиотеке нет готового решения для этого, но это не так сложно сделать самостоятельно.
Нам нужен этот интерфейс http.File
:
type File interface {
io.Closer
io.Reader
io.Seeker
Readdir(count int) ([]os.FileInfo, error)
Stat() (os.FileInfo, error)
}
Обратите внимание, что мы можем использовать bytes.Reader
для выполнения тяжелой задачи, поскольку только она реализует io.Reader
и io.Seeker
,io.Closer
может быть noop, а Readdir()
может возвращать nil, nil
, поскольку мы высмеиваем файл, а не каталог, его Readdir()
даже не будет вызываться.
Самая сложная часть - это смоделировать Stat()
, чтобы вернуть значение, которое реализует os.FileInfo
.
Вот простой насмешливый FileInfo
:
type myFileInfo struct {
name string
data []byte
}
func (mif myFileInfo) Name() string { return mif.name }
func (mif myFileInfo) Size() int64 { return int64(len(mif.data)) }
func (mif myFileInfo) Mode() os.FileMode { return 0444 } // Read for all
func (mif myFileInfo) ModTime() time.Time { return time.Time{} } // Return anything
func (mif myFileInfo) IsDir() bool { return false }
func (mif myFileInfo) Sys() interface{} { return nil }
И с этим у нас есть все для создания нашего смоделированного http.File
:
type MyFile struct {
*bytes.Reader
mif myFileInfo
}
func (mf *MyFile) Close() error { return nil } // Noop, nothing to do
func (mf *MyFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil // We are not a directory but a single file
}
func (mf *MyFile) Stat() (os.FileInfo, error) {
return mf.mif, nil
}
Пример его использования (попробуйте на Go Playground ):
data := []byte{0, 1, 2, 3}
mf := &MyFile{
Reader: bytes.NewReader(data),
mif: myFileInfo{
name: "somename.txt",
data: data,
},
}
var f http.File = mf
_ = f