func (fs *LocalFS) Put(userID string, reader io.Reader) (avatar string, err error) {
	if reader == nil {
		return "", errors.New("empty reader")
	}
	id := encodeID(userID)
	location := fs.location(id)  
	if e := os.MkdirAll(location, 0750); e != nil {
		return "", errors.Wrapf(e, "failed to mkdir avatar location %s", location)
	}
	avFile := path.Join(location, id+imgSfx)
	fh, err := os.Create(avFile)
	if err != nil {
		return "", errors.Wrapf(err, "can't create file %s", avFile)
	}
	defer func() {
		if e := fh.Close(); e != nil {
			err = errors.Wrapf(err, "can't close avatar file %s", avFile)
		}
	}()
	if _, err = io.Copy(fh, reader); err != nil {
		return "", errors.Wrapf(err, "can't save file %s", avFile)
	}
	return id + imgSfx, nil
}
Put avatar for userID to file and return avatar's file name (base), like 12345678.image
userID can be avatarID as well, in this case encoding just strip .image prefix
package avatar
import (
	"fmt"
	"hash/crc64"
	"io"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"github.com/pkg/errors"
)
type LocalFS struct {
	storePath string
	ctcTable  *crc64.Table
	once      sync.Once
}
func NewLocalFS(storePath string) *LocalFS {
	return &LocalFS{storePath: storePath}
}