func (mfs *MemFS) AddFile(internalPath, externalPath string) (node *Node, err error) {
	if len(internalPath) == 0 {
		return nil, nil
	}
	logp := "AddFile"
	fi, err := os.Stat(externalPath)
	if err != nil {
		return nil, fmt.Errorf("%s: %w", logp, err)
	}
	var parent *Node
	internalPath = filepath.ToSlash(filepath.Clean(internalPath))
	paths := strings.Split(internalPath, "/")
	base := paths[len(paths)-1]
	paths = paths[:len(paths)-1]
	path := ""
	for _, p := range paths {
		path = filepath.Join(path, p)
		node, _ := mfs.Get(path)
		if node != nil {
			parent = node
			continue
		}
		node = &Node{
			SysPath: path,
			Path:    path,
			name:    p,
			mode:    os.ModeDir,
			Parent:  parent,
		}
		node.generateFuncName(path)
		if parent == nil {
			mfs.Root.Childs = append(mfs.Root.Childs, node)
		} else {
			parent.Childs = append(parent.Childs, node)
		}
		mfs.PathNodes.Set(node.Path, node)
		parent = node
	}
	path = filepath.Join(path, base)
	node = &Node{
		SysPath: externalPath,
		Path:    path,
		name:    base,
		modTime: fi.ModTime(),
		mode:    fi.Mode(),
		size:    fi.Size(),
		Parent:  parent,
	}
	node.generateFuncName(path)
	err = node.updateContent(mfs.Opts.MaxFileSize)
	if err != nil {
		return nil, fmt.Errorf("%s: %w", logp, err)
	}
	err = node.updateContentType()
	if err != nil {
		return nil, fmt.Errorf("%s: %w", logp, err)
	}
	parent.Childs = append(parent.Childs, node)
	mfs.PathNodes.Set(node.Path, node)
	return node, nil
}
AddFile add the external file directly as internal file.
If the internal file is already exist it will be replaced.
Any directories in the internal path will be generated automatically if its
not exist.
package memfs
import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strings"
	"time"
	libbytes "github.com/shuLhan/share/lib/bytes"
	libints "github.com/shuLhan/share/lib/ints"
	"github.com/shuLhan/share/lib/sanitize"
	libstrings "github.com/shuLhan/share/lib/strings"
)
const (
	EncodingGzip = "gzip"
	defContentType = "text/plain"  
)
type MemFS struct {
	http.FileSystem
	PathNodes *PathNode
	Root      *Node
	Opts      *Options
	incRE     []*regexp.Regexp
	excRE     []*regexp.Regexp
}
func Merge(params ...*MemFS) (merged *MemFS) {
	merged = &MemFS{
		PathNodes: NewPathNode(),
		Root: &Node{
			SysPath: "..",
			Path:    "/",
			mode:    2147484141,
		},
		Opts: &Options{},
	}
	merged.PathNodes.Set("/", merged.Root)
	for _, mfs := range params {
		for _, child := range mfs.Root.Childs {
			gotNode := merged.PathNodes.Get(child.Path)
			if gotNode != nil {
				continue
			}
			merged.Root.AddChild(child)
		}
		paths := mfs.PathNodes.Paths()
		for _, path := range paths {
			if path == "/" {
				continue
			}
			gotNode := merged.PathNodes.Get(path)
			if gotNode == nil {
				merged.PathNodes.Set(path, mfs.PathNodes.Get(path))
			}
		}
	}
	return merged
}
func New(opts *Options) (mfs *MemFS, err error) {
	logp := "New"
	if opts == nil {
		opts = &Options{}
	}
	opts.init()
	mfs = &MemFS{
		PathNodes: NewPathNode(),
		Opts:      opts,
	}
	for _, inc := range opts.Includes {
		re, err := regexp.Compile(inc)
		if err != nil {
			return nil, fmt.Errorf("%s: %w", logp, err)
		}
		mfs.incRE = append(mfs.incRE, re)
	}
	for _, exc := range opts.Excludes {
		re, err := regexp.Compile(exc)
		if err != nil {
			return nil, fmt.Errorf("%s: %w", logp, err)
		}
		mfs.excRE = append(mfs.excRE, re)
	}
	err = mfs.mount()
	if err != nil {
		return nil, fmt.Errorf("%s: %w", logp, err)
	}
	return mfs, nil
}
func (mfs *MemFS) AddChild(parent *Node, fi os.FileInfo) (child *Node, err error) {
	sysPath := filepath.Join(parent.SysPath, fi.Name())
	if !mfs.isIncluded(sysPath, fi.Mode()) {
		return nil, nil
	}
	child, err = parent.addChild(sysPath, fi, mfs.Opts.MaxFileSize)
	if err != nil {
		log.Printf("AddChild %s: %s", fi.Name(), err.Error())
		return nil, nil
	}
	mfs.PathNodes.Set(child.Path, child)
	return child, nil
}