mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
up
This commit is contained in:
@ -8,6 +8,9 @@
|
||||
package gres
|
||||
|
||||
var (
|
||||
// Default resource file system.
|
||||
defaultFS = NewResFS()
|
||||
|
||||
// Default resource object.
|
||||
defaultResource = Instance()
|
||||
)
|
||||
@ -16,18 +19,18 @@ var (
|
||||
// The unnecessary parameter `prefix` indicates the prefix
|
||||
// for each file storing into current resource object.
|
||||
func Add(content string, prefix ...string) error {
|
||||
return defaultResource.Add(content, prefix...)
|
||||
return defaultFS.Add(content, prefix...)
|
||||
}
|
||||
|
||||
// Load loads, unpacks and adds the data from `path` into the default resource object.
|
||||
// The unnecessary parameter `prefix` indicates the prefix
|
||||
// for each file storing into current resource object.
|
||||
func Load(path string, prefix ...string) error {
|
||||
return defaultResource.Load(path, prefix...)
|
||||
return defaultFS.Load(path, prefix...)
|
||||
}
|
||||
|
||||
// Get returns the file with given path.
|
||||
func Get(path string) *File {
|
||||
func Get(path string) File {
|
||||
return defaultResource.Get(path)
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ func Get(path string) *File {
|
||||
// it then does index files searching under this directory.
|
||||
//
|
||||
// GetWithIndex is usually used for http static file service.
|
||||
func GetWithIndex(path string, indexFiles []string) *File {
|
||||
func GetWithIndex(path string, indexFiles []string) File {
|
||||
return defaultResource.GetWithIndex(path, indexFiles)
|
||||
}
|
||||
|
||||
@ -60,7 +63,7 @@ func IsEmpty() bool {
|
||||
// using the ',' symbol to separate multiple patterns.
|
||||
//
|
||||
// It scans directory recursively if given parameter `recursive` is true.
|
||||
func ScanDir(path string, pattern string, recursive ...bool) []*File {
|
||||
func ScanDir(path string, pattern string, recursive ...bool) []File {
|
||||
return defaultResource.ScanDir(path, pattern, recursive...)
|
||||
}
|
||||
|
||||
@ -68,7 +71,7 @@ func ScanDir(path string, pattern string, recursive ...bool) []*File {
|
||||
// It scans directory recursively if given parameter `recursive` is true.
|
||||
//
|
||||
// Note that it returns only files, exclusive of directories.
|
||||
func ScanDirFile(path string, pattern string, recursive ...bool) []*File {
|
||||
func ScanDirFile(path string, pattern string, recursive ...bool) []File {
|
||||
return defaultResource.ScanDirFile(path, pattern, recursive...)
|
||||
}
|
||||
|
||||
|
||||
@ -11,104 +11,71 @@ import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// A File provides access to a single file.
|
||||
// The File interface is the minimum implementation required of the file.
|
||||
// Directory files should also implement [ReadDirFile].
|
||||
// A file may implement [io.ReaderAt] or [io.Seeker] as optimizations.
|
||||
type File interface {
|
||||
Name() string
|
||||
Path() string
|
||||
Content() []byte
|
||||
FileInfo() os.FileInfo
|
||||
Export(dst string, option ...ExportOption) error
|
||||
|
||||
// For http.File implementation.
|
||||
|
||||
Readdir(count int) ([]os.FileInfo, error)
|
||||
io.ReadSeekCloser
|
||||
}
|
||||
|
||||
// File implements the interface fs.File.
|
||||
type File struct {
|
||||
name string // Name is the file name
|
||||
path string // Path is the file path
|
||||
file os.FileInfo // FileInfo is the underlying file info
|
||||
reader io.Reader // Reader is the file content reader
|
||||
resource []byte // Resource is the file content in binary format
|
||||
fs FS // FS is the file system that contains this file
|
||||
type localFile struct {
|
||||
name string // Name is the file name
|
||||
path string // Path is the file path
|
||||
content []byte // file content
|
||||
file os.FileInfo // FileInfo is the underlying file info
|
||||
fs FS // FS is the file system that contains this file
|
||||
mu sync.Mutex // mu protects concurrent access to the file
|
||||
}
|
||||
|
||||
// Name returns the name of the file
|
||||
func (f *File) Name() string {
|
||||
func (f *localFile) Name() string {
|
||||
return f.name
|
||||
}
|
||||
|
||||
// Path returns the path of the file
|
||||
func (f *File) Path() string {
|
||||
func (f *localFile) Path() string {
|
||||
return f.path
|
||||
}
|
||||
|
||||
// Open opens the file for reading
|
||||
func (f *File) Open() error {
|
||||
if f.reader == nil && len(f.resource) > 0 {
|
||||
f.reader = bytes.NewReader(f.resource)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the file
|
||||
func (f *File) Close() error {
|
||||
if closer, ok := f.reader.(io.Closer); ok {
|
||||
return closer.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read reads up to len(p) bytes into p
|
||||
func (f *File) Read(p []byte) (n int, err error) {
|
||||
if f.reader == nil {
|
||||
if err := f.Open(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return f.reader.Read(p)
|
||||
}
|
||||
|
||||
// Seek implements the io.Seeker interface
|
||||
func (f *File) Seek(offset int64, whence int) (int64, error) {
|
||||
if seeker, ok := f.reader.(io.Seeker); ok {
|
||||
return seeker.Seek(offset, whence)
|
||||
}
|
||||
return 0, fs.ErrInvalid
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo describing this file
|
||||
func (f *File) FileInfo() os.FileInfo {
|
||||
func (f *localFile) FileInfo() os.FileInfo {
|
||||
return f.file
|
||||
}
|
||||
|
||||
// Stat returns the FileInfo structure describing file
|
||||
func (f *File) Stat() (os.FileInfo, error) {
|
||||
return f.file, nil
|
||||
}
|
||||
|
||||
// Content returns the file content
|
||||
func (f *File) Content() []byte {
|
||||
if len(f.resource) > 0 {
|
||||
return f.resource
|
||||
}
|
||||
buffer := new(bytes.Buffer)
|
||||
if err := f.Open(); err != nil {
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := io.Copy(buffer, f); err != nil {
|
||||
return nil
|
||||
}
|
||||
f.resource = buffer.Bytes()
|
||||
return f.resource
|
||||
func (f *localFile) Content() []byte {
|
||||
return f.content
|
||||
}
|
||||
|
||||
// Export exports and saves all its sub files to specified system path `dst` recursively.
|
||||
func (f *File) Export(dst string, option ...ExportOption) error {
|
||||
func (f *localFile) Export(dst string, option ...ExportOption) error {
|
||||
var (
|
||||
err error
|
||||
name string
|
||||
path string
|
||||
exportOption ExportOption
|
||||
exportFiles []*File
|
||||
exportFiles []File
|
||||
)
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
exportFiles = f.fs.ScanDir(f.path, "*", true)
|
||||
} else {
|
||||
@ -128,7 +95,7 @@ func (f *File) Export(dst string, option ...ExportOption) error {
|
||||
continue
|
||||
}
|
||||
path = gfile.Join(dst, name)
|
||||
if exportFile.FileInfo().IsDir() {
|
||||
if f.FileInfo().IsDir() {
|
||||
err = gfile.Mkdir(path)
|
||||
} else {
|
||||
err = gfile.PutBytes(path, exportFile.Content())
|
||||
@ -140,8 +107,51 @@ func (f *File) Export(dst string, option ...ExportOption) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements interface of http.File.
|
||||
func (f *localFile) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Readdir implements Readdir interface of http.File.
|
||||
func (f *localFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
files := f.fs.ScanDir(f.Name(), "*", false)
|
||||
if len(files) > 0 {
|
||||
if count <= 0 || count > len(files) {
|
||||
count = len(files)
|
||||
}
|
||||
infos := make([]os.FileInfo, count)
|
||||
for k, v := range files {
|
||||
infos[k] = v.FileInfo()
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Read implements the io.Reader interface.
|
||||
func (f *localFile) Read(b []byte) (n int, err error) {
|
||||
reader := bytes.NewReader(f.Content())
|
||||
if n, err = reader.Read(b); err != nil {
|
||||
err = gerror.Wrapf(err, `read content failed`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Seek implements the io.Seeker interface.
|
||||
func (f *localFile) Seek(offset int64, whence int) (n int64, err error) {
|
||||
reader := bytes.NewReader(f.Content())
|
||||
if n, err = reader.Seek(offset, whence); err != nil {
|
||||
err = gerror.Wrapf(err, `seek failed for offset %d, whence %d`, offset, whence)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *localFile) getReader() (io.ReadSeeker, error) {
|
||||
return bytes.NewReader(f.Content()), nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (f *File) MarshalJSON() ([]byte, error) {
|
||||
func (f *localFile) MarshalJSON() ([]byte, error) {
|
||||
info := f.FileInfo()
|
||||
return gjson.Marshal(map[string]interface{}{
|
||||
"name": f.name,
|
||||
@ -155,7 +165,7 @@ func (f *File) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// fileInfo is the internal implementation of os.FileInfo interface.
|
||||
type fileInfo struct {
|
||||
file *File
|
||||
file *localFile
|
||||
}
|
||||
|
||||
// Name returns the base name of the file.
|
||||
|
||||
@ -9,14 +9,14 @@ package gres
|
||||
// FS is the interface that defines a virtual file system.
|
||||
type FS interface {
|
||||
// Get returns the file with given path.
|
||||
Get(path string) *File
|
||||
Get(path string) File
|
||||
|
||||
// IsEmpty checks and returns whether the resource is empty.
|
||||
IsEmpty() bool
|
||||
|
||||
// ScanDir returns the files under the given path,
|
||||
// the parameter `path` should be a folder type.
|
||||
ScanDir(path string, pattern string, recursive ...bool) []*File
|
||||
ScanDir(path string, pattern string, recursive ...bool) []File
|
||||
}
|
||||
|
||||
// ExportOption contains options for Export.
|
||||
|
||||
@ -8,6 +8,7 @@ package gres
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// MixedFS implements the FS interface by combining StdFS and ResFS.
|
||||
@ -17,6 +18,8 @@ type MixedFS struct {
|
||||
resFS *ResFS
|
||||
}
|
||||
|
||||
var _ FS = (*MixedFS)(nil)
|
||||
|
||||
// NewMixedFS creates and returns a new MixedFS.
|
||||
func NewMixedFS(stdFs fs.FS, resFS *ResFS) *MixedFS {
|
||||
return &MixedFS{
|
||||
@ -26,7 +29,7 @@ func NewMixedFS(stdFs fs.FS, resFS *ResFS) *MixedFS {
|
||||
}
|
||||
|
||||
// Get returns the file with given path.
|
||||
func (fs *MixedFS) Get(path string) *File {
|
||||
func (fs *MixedFS) Get(path string) File {
|
||||
if file := fs.resFS.Get(path); file != nil {
|
||||
return file
|
||||
}
|
||||
@ -40,15 +43,15 @@ func (fs *MixedFS) IsEmpty() bool {
|
||||
|
||||
// ScanDir returns the files under the given path,
|
||||
// the parameter `path` should be a folder type.
|
||||
func (fs *MixedFS) ScanDir(path string, pattern string, recursive ...bool) []*File {
|
||||
func (fs *MixedFS) ScanDir(path string, pattern string, recursive ...bool) []File {
|
||||
var (
|
||||
filesMap = make(map[string]*File)
|
||||
files = make([]*File, 0)
|
||||
filesMap = make(map[string]File)
|
||||
files = make([]File, 0)
|
||||
)
|
||||
|
||||
// Get files from ResFS
|
||||
defaultFiles := fs.resFS.ScanDir(path, pattern, recursive...)
|
||||
for _, file := range defaultFiles {
|
||||
resFiles := fs.resFS.ScanDir(path, pattern, recursive...)
|
||||
for _, file := range resFiles {
|
||||
if _, exists := filesMap[file.Path()]; !exists {
|
||||
filesMap[file.Path()] = file
|
||||
}
|
||||
@ -56,32 +59,21 @@ func (fs *MixedFS) ScanDir(path string, pattern string, recursive ...bool) []*Fi
|
||||
|
||||
// Get files from StdFS
|
||||
stdFiles := fs.stdFS.ScanDir(path, pattern, recursive...)
|
||||
if len(stdFiles) > 0 {
|
||||
|
||||
}
|
||||
for _, file := range stdFiles {
|
||||
filesMap[file.Path()] = file
|
||||
}
|
||||
|
||||
// Convert map to slice
|
||||
for _, file := range filesMap {
|
||||
files = append(files, file)
|
||||
// Convert map to slice and sort by path
|
||||
paths := make([]string, 0, len(filesMap))
|
||||
for filePath := range filesMap {
|
||||
paths = append(paths, filePath)
|
||||
}
|
||||
sort.Strings(paths)
|
||||
|
||||
// Build sorted result
|
||||
for _, filePath := range paths {
|
||||
files = append(files, filesMap[filePath])
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
// ScanDirFile returns all sub-files with absolute paths of given `path`,
|
||||
// It scans directory recursively if given parameter `recursive` is true.
|
||||
func (fs *MixedFS) ScanDirFile(path string, pattern string, recursive ...bool) []*File {
|
||||
return fs.ScanDir(path, pattern, recursive...)
|
||||
}
|
||||
|
||||
// Export exports and saves specified path `src` and all its sub files
|
||||
// to specified system path `dst` recursively.
|
||||
func (fs *MixedFS) Export(src, dst string, option ...ExportOption) error {
|
||||
if file := fs.Get(src); file != nil {
|
||||
return file.Export(dst, option...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@ type ResFS struct {
|
||||
tree *gtree.BTree // The tree storing all resource files.
|
||||
}
|
||||
|
||||
var _ FS = (*ResFS)(nil)
|
||||
|
||||
const (
|
||||
defaultTreeM = 100
|
||||
)
|
||||
@ -37,7 +39,7 @@ func NewResFS() *ResFS {
|
||||
}
|
||||
|
||||
// Get returns the file with given path.
|
||||
func (fs *ResFS) Get(path string) *File {
|
||||
func (fs *ResFS) Get(path string) File {
|
||||
if path == "" {
|
||||
return nil
|
||||
}
|
||||
@ -50,7 +52,7 @@ func (fs *ResFS) Get(path string) *File {
|
||||
}
|
||||
result := fs.tree.Get(path)
|
||||
if result != nil {
|
||||
return result.(*File)
|
||||
return result.(File)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -62,7 +64,7 @@ func (fs *ResFS) IsEmpty() bool {
|
||||
|
||||
// ScanDir returns the files under the given path,
|
||||
// the parameter `path` should be a folder type.
|
||||
func (fs *ResFS) ScanDir(path string, pattern string, recursive ...bool) []*File {
|
||||
func (fs *ResFS) ScanDir(path string, pattern string, recursive ...bool) []File {
|
||||
isRecursive := false
|
||||
if len(recursive) > 0 {
|
||||
isRecursive = recursive[0]
|
||||
@ -77,7 +79,7 @@ func (fs *ResFS) ScanDir(path string, pattern string, recursive ...bool) []*File
|
||||
// using the ',' symbol to separate multiple patterns.
|
||||
//
|
||||
// It scans directory recursively if given parameter `recursive` is true.
|
||||
func (fs *ResFS) doScanDir(path string, pattern string, recursive bool) []*File {
|
||||
func (fs *ResFS) doScanDir(path string, pattern string, recursive bool) []File {
|
||||
path = strings.ReplaceAll(path, "\\", "/")
|
||||
path = strings.ReplaceAll(path, "//", "/")
|
||||
if path != "/" {
|
||||
@ -86,7 +88,7 @@ func (fs *ResFS) doScanDir(path string, pattern string, recursive bool) []*File
|
||||
}
|
||||
}
|
||||
var (
|
||||
files = make([]*File, 0)
|
||||
files = make([]File, 0)
|
||||
patterns = strings.Split(pattern, ",")
|
||||
)
|
||||
for i := 0; i < len(patterns); i++ {
|
||||
@ -102,7 +104,7 @@ func (fs *ResFS) doScanDir(path string, pattern string, recursive bool) []*File
|
||||
// Walk through the tree to find matching files
|
||||
fs.tree.IteratorAsc(func(key, value interface{}) bool {
|
||||
var (
|
||||
file = value.(*File)
|
||||
file = value.(File)
|
||||
filePath = key.(string)
|
||||
)
|
||||
|
||||
@ -144,7 +146,7 @@ func (fs *ResFS) Add(content string, prefix ...string) error {
|
||||
namePrefix = prefix[0]
|
||||
}
|
||||
for i := 0; i < len(files); i++ {
|
||||
files[i].fs = fs
|
||||
files[i].(*localFile).fs = fs
|
||||
fs.tree.Set(namePrefix+files[i].Path(), files[i])
|
||||
}
|
||||
intlog.Printf(context.TODO(), "Add %d files to resource manager", fs.tree.Size())
|
||||
@ -164,7 +166,7 @@ func (fs *ResFS) Load(path string, prefix ...string) error {
|
||||
func (fs *ResFS) Dump() {
|
||||
var info os.FileInfo
|
||||
fs.tree.Iterator(func(key, value interface{}) bool {
|
||||
info = value.(*File).FileInfo()
|
||||
info = value.(File).FileInfo()
|
||||
intlog.Printf(
|
||||
context.TODO(),
|
||||
"%v %8s %s",
|
||||
|
||||
@ -20,6 +20,8 @@ type StdFS struct {
|
||||
fs fs.FS
|
||||
}
|
||||
|
||||
var _ FS = (*StdFS)(nil)
|
||||
|
||||
// NewStdFS creates and returns a new StdFS.
|
||||
func NewStdFS(fs fs.FS) *StdFS {
|
||||
return &StdFS{
|
||||
@ -28,7 +30,7 @@ func NewStdFS(fs fs.FS) *StdFS {
|
||||
}
|
||||
|
||||
// Get returns the file with given path.
|
||||
func (fs *StdFS) Get(path string) *File {
|
||||
func (fs *StdFS) Get(path string) File {
|
||||
f, err := fs.fs.Open(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -37,6 +39,7 @@ func (fs *StdFS) Get(path string) *File {
|
||||
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -46,12 +49,12 @@ func (fs *StdFS) Get(path string) *File {
|
||||
return nil
|
||||
}
|
||||
|
||||
file := &File{
|
||||
name: info.Name(),
|
||||
path: path,
|
||||
file: info,
|
||||
resource: content,
|
||||
fs: fs,
|
||||
file := &localFile{
|
||||
name: info.Name(),
|
||||
path: path,
|
||||
file: info,
|
||||
content: content,
|
||||
fs: fs,
|
||||
}
|
||||
return file
|
||||
}
|
||||
@ -72,9 +75,9 @@ func (fs *StdFS) IsEmpty() bool {
|
||||
|
||||
// ScanDir returns the files under the given path,
|
||||
// the parameter `path` should be a folder type.
|
||||
func (fs *StdFS) ScanDir(path string, pattern string, recursive ...bool) []*File {
|
||||
func (fs *StdFS) ScanDir(path string, pattern string, recursive ...bool) []File {
|
||||
var (
|
||||
files = make([]*File, 0)
|
||||
files = make([]File, 0)
|
||||
isRecursive = len(recursive) > 0 && recursive[0]
|
||||
)
|
||||
err := fs.walkDir(path, func(path string, d os.DirEntry, err error) error {
|
||||
|
||||
@ -11,6 +11,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gbase64"
|
||||
"github.com/gogf/gf/v2/encoding/gcompress"
|
||||
@ -129,7 +130,7 @@ func PackToGoFileWithOption(srcPath, goFilePath, pkgName string, option Option)
|
||||
}
|
||||
|
||||
// Unpack unpacks the content specified by `path` to []*File.
|
||||
func Unpack(path string) ([]*File, error) {
|
||||
func Unpack(path string) ([]File, error) {
|
||||
realPath, err := gfile.Search(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -137,8 +138,8 @@ func Unpack(path string) ([]*File, error) {
|
||||
return UnpackContent(gfile.GetContents(realPath))
|
||||
}
|
||||
|
||||
// UnpackContent unpacks the content to []*File.
|
||||
func UnpackContent(content string) ([]*File, error) {
|
||||
// UnpackContent unpacks the content to []File.
|
||||
func UnpackContent(content string) ([]File, error) {
|
||||
var (
|
||||
err error
|
||||
data []byte
|
||||
@ -171,15 +172,15 @@ func UnpackContent(content string) ([]*File, error) {
|
||||
err = gerror.Wrapf(err, `create zip reader failed`)
|
||||
return nil, err
|
||||
}
|
||||
array := make([]*File, len(reader.File))
|
||||
array := make([]File, len(reader.File))
|
||||
for i, file := range reader.File {
|
||||
array[i] = &File{
|
||||
name: file.Name,
|
||||
path: file.Name,
|
||||
file: file.FileInfo(),
|
||||
reader: nil,
|
||||
resource: nil,
|
||||
fs: nil,
|
||||
array[i] = &localFile{
|
||||
name: file.Name,
|
||||
path: file.Name,
|
||||
content: data,
|
||||
file: file.FileInfo(),
|
||||
fs: nil,
|
||||
mu: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
return array, nil
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gres
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// Close implements interface of http.File.
|
||||
func (f *File) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Readdir implements Readdir interface of http.File.
|
||||
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
|
||||
files := f.resource.ScanDir(f.Name(), "*", false)
|
||||
if len(files) > 0 {
|
||||
if count <= 0 || count > len(files) {
|
||||
count = len(files)
|
||||
}
|
||||
infos := make([]os.FileInfo, count)
|
||||
for k, v := range files {
|
||||
infos[k] = v.FileInfo()
|
||||
}
|
||||
return infos, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Stat implements Stat interface of http.File.
|
||||
func (f *File) Stat() (os.FileInfo, error) {
|
||||
return f.FileInfo(), nil
|
||||
}
|
||||
|
||||
// Read implements the io.Reader interface.
|
||||
func (f *File) Read(b []byte) (n int, err error) {
|
||||
reader, err := f.getReader()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n, err = reader.Read(b); err != nil {
|
||||
err = gerror.Wrapf(err, `read content failed`)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Seek implements the io.Seeker interface.
|
||||
func (f *File) Seek(offset int64, whence int) (n int64, err error) {
|
||||
reader, err := f.getReader()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n, err = reader.Seek(offset, whence); err != nil {
|
||||
err = gerror.Wrapf(err, `seek failed for offset %d, whence %d`, offset, whence)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *File) getReader() (*bytes.Reader, error) {
|
||||
if f.reader == nil {
|
||||
f.reader = bytes.NewReader(f.Content())
|
||||
}
|
||||
return f.reader, nil
|
||||
}
|
||||
@ -26,6 +26,6 @@ func Instance(name ...string) *Resource {
|
||||
key = name[0]
|
||||
}
|
||||
return instances.GetOrSetFuncLock(key, func() interface{} {
|
||||
return New()
|
||||
return NewWithFS(defaultFS)
|
||||
}).(*Resource)
|
||||
}
|
||||
|
||||
@ -30,14 +30,19 @@ func NewWithFS(fs FS) *Resource {
|
||||
}
|
||||
}
|
||||
|
||||
// SetFS sets the underlying file system implementation.
|
||||
func (r *Resource) SetFS(fs FS) {
|
||||
r.fs = fs
|
||||
}
|
||||
|
||||
// Get returns the file with given path.
|
||||
func (r *Resource) Get(path string) *File {
|
||||
func (r *Resource) Get(path string) File {
|
||||
return r.fs.Get(path)
|
||||
}
|
||||
|
||||
// GetWithIndex searches file with `path`, if the file is directory
|
||||
// it then does index files searching under this directory.
|
||||
func (r *Resource) GetWithIndex(path string, indexFiles []string) *File {
|
||||
func (r *Resource) GetWithIndex(path string, indexFiles []string) File {
|
||||
// Necessary for double char '/' replacement in prefix.
|
||||
path = strings.ReplaceAll(path, "\\", "/")
|
||||
path = strings.ReplaceAll(path, "//", "/")
|
||||
@ -48,7 +53,7 @@ func (r *Resource) GetWithIndex(path string, indexFiles []string) *File {
|
||||
}
|
||||
if file := r.fs.Get(path); file != nil {
|
||||
if len(indexFiles) > 0 && file.FileInfo().IsDir() {
|
||||
var f *File
|
||||
var f File
|
||||
for _, name := range indexFiles {
|
||||
if f = r.fs.Get(path + "/" + name); f != nil {
|
||||
return f
|
||||
@ -80,15 +85,15 @@ func (r *Resource) IsEmpty() bool {
|
||||
}
|
||||
|
||||
// ScanDir returns the files under the given path, the parameter `path` should be a folder type.
|
||||
func (r *Resource) ScanDir(path string, pattern string, recursive ...bool) []*File {
|
||||
func (r *Resource) ScanDir(path string, pattern string, recursive ...bool) []File {
|
||||
return r.fs.ScanDir(path, pattern, recursive...)
|
||||
}
|
||||
|
||||
// ScanDirFile returns all sub-files with absolute paths of given `path`,
|
||||
// It scans directory recursively if given parameter `recursive` is true.
|
||||
func (r *Resource) ScanDirFile(path string, pattern string, recursive ...bool) []*File {
|
||||
func (r *Resource) ScanDirFile(path string, pattern string, recursive ...bool) []File {
|
||||
var (
|
||||
result = make([]*File, 0)
|
||||
result = make([]File, 0)
|
||||
files = r.fs.ScanDir(path, pattern, recursive...)
|
||||
)
|
||||
for _, file := range files {
|
||||
|
||||
Reference in New Issue
Block a user