file/filetools.go

303 lines
7.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package file
import (
"encoding/json"
"fmt"
"io"
"os"
"os/user"
"path/filepath"
"regexp"
"strings"
"github.com/gofrs/flock"
)
// Получить текущую рабочую папку
//
// 0.1.0
func GetCWD() string {
wd, e := os.Getwd()
if e != nil {
return ""
}
return wd
}
// Получить имя исполняемого файла
//
// 0.1.0
func GetBinName() string {
bn, e := os.Executable()
if e != nil {
return ""
}
return filepath.Base(bn)
}
// Получить папку исполняемого файла
//
// 0.1.0
func GetBinDir() string {
bn, e := os.Executable()
if e != nil {
return ""
}
return filepath.Dir(bn)
}
// Получить домашнюю папку
//
// 0.1.0
func GetHome() string {
u, e := user.Current()
if e != nil {
return ""
}
return u.HomeDir
}
// Развернуть путь до полного
//
// 0.1.0
//
// Префиксы:
//
// "." - заменяется папкой исполняемого файла
// "~" - заменяется домашней папкой пользователя
// "/" - замен не производится
// "" - дополняется текущей рабочей папкой
func RealPath(path string) string {
path = ClearPath(path)
rpath := ""
if len(path) < 1 {
return GetCWD()
}
switch path[0] {
case '.':
rpath = GetBinDir() + "/" + strings.TrimLeft(path, "./")
case '~':
rpath = GetHome() + "/" + strings.TrimLeft(path, "~/")
case '/':
rpath = path
default:
rpath = GetCWD() + "/" + path
}
//rpath = strings.ReplaceAll(rpath, "//", "/")
rpath = ClearPath(rpath)
return rpath
}
var (
rs = regexp.MustCompile("[/]+")
rd = regexp.MustCompile("[.]+")
)
// Очистить путь от лишних символов
func ClearPath(path string) string {
out := rd.ReplaceAllString(rs.ReplaceAllString(path, "/"), ".")
return out
}
// Получить расширение файла
//
// 0.1.1
func Ext(file string) string {
fpa := strings.Split(file, "/")
fa := strings.Split(fpa[len(fpa)-1], ".")
if len(fa) < 2 {
return ""
}
return fa[len(fa)-1]
}
// Существует ли файл
//
// 0.1.0
func Exists(file string) bool {
if _, e := os.Stat(RealPath(file)); os.IsNotExist(e) {
return false
}
return true
}
// Загрузить файл
//
// 0.2.0
func Load(file string) ([]byte, error) {
if !Exists(RealPath(file)) {
//return nil, errs.RaiseError(ErrFileNotFound, "File '"+file+"' not found")
return nil, fmt.Errorf("file not found: %s", file)
}
ret, e := os.ReadFile(RealPath(file))
if e != nil {
//return nil, errs.RaiseError(ErrFileRead, "Error read file '"+file+"': "+e.Error())
return nil, fmt.Errorf("error read file '%s': %v", file, e)
}
return ret, nil
}
// Загрузить и распарсить JSON-файл
//
// 0.2.0
func LoadJSON(file string) (data interface{}, err error) {
src, err := Load(file)
if err != nil {
return nil, err
}
e := json.Unmarshal(src, &data)
if e != nil {
//return nil, errs.RaiseError(ErrParseJSON, "Error parse file '"+file+"': "+e.Error())
return nil, fmt.Errorf("error parse file '%s': %v", file, e)
}
return
}
// Загрузить структуру из JSON-файла
//
// 0.2.5
func LoadStruct(fName string, res any) error {
src, e := Load(fName)
if e != nil {
return e
}
if e := json.Unmarshal(src, &res); e != nil {
return e
}
return nil
}
// Сохранить файл, создать путь если не существует
//
// 0.2.0
func Save(file string, data []byte, perms ...os.FileMode) error {
fName := RealPath(file)
fPath := filepath.Dir(fName)
pa := getPerms(perms)
if e := os.MkdirAll(fPath, pa[1]); e != nil {
//return errs.RaiseError(ErrCreatePath, "Error create path '"+fPath+"': "+e.Error())
return fmt.Errorf("error create path '%s': %v", fPath, e)
}
if e := os.WriteFile(fName, data, pa[0]); e != nil {
//return errs.RaiseError(ErrFileWrite, "Error write file '"+fName+"': "+e.Error())
return fmt.Errorf("error write file '%s': %v", file, e)
}
return nil
}
// Сохранить JSON-файл
//
// 0.2.0
func SaveJSON(file string, data interface{}, perms ...os.FileMode) error {
jsonData, e := json.Marshal(data)
if e != nil {
//return errs.RaiseError(ErrParseJSON, "Error parse data for file '"+file+"': "+e.Error())
return fmt.Errorf("error marshal data for file '%s': %v", file, e)
}
return Save(file, jsonData, perms...)
}
// Разобрать массив прав
//
// 0.1.3
func getPerms(perms []os.FileMode) (pa []os.FileMode) {
pa = make([]os.FileMode, 0)
if len(perms) > 0 {
pa = append(pa, perms[0])
} else {
pa = append(pa, 0664)
}
if len(perms) > 1 {
pa = append(pa, perms[1])
} else {
pa = append(pa, 0775)
}
return pa
}
// Добавить в файл, создать если не существует
//
// 0.2.0
func Append(file string, data []byte, perms ...os.FileMode) error {
fName := RealPath(file)
f, err := OpenCreate(fName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, perms...)
if err != nil {
//return errs.UpError(err)
return err
}
defer f.Close()
lock := flock.New(fName)
if e := lock.Lock(); e != nil {
//return errs.RaiseError(ErrFileLock, e.Error())
return fmt.Errorf("error lock file '%s': %v", fName, e)
}
defer lock.Unlock()
f.Write(data)
return nil
}
// Удалить файл
//
// 0.2.0
func Delete(file string) error {
if e := os.Remove(RealPath(file)); e != nil {
//return errs.RaiseError(ErrFileDelete, "Error delete file '"+file+"': "+e.Error())
return fmt.Errorf("error delete file '%s': %v", RealPath(file), e)
}
return nil
}
// Очистить файл
// 0.2.4
func Truncate(file string) error {
fName := RealPath(file)
lock := flock.New(fName)
if e := lock.Lock(); e != nil {
return fmt.Errorf("error lock file '%s': %v", fName, e)
}
defer lock.Unlock()
return os.Truncate(RealPath(file), 0)
}
// Открыть файл, создать если не существует, вместе с путем
//
// 0.2.0
func OpenCreate(file string, flag int, perms ...os.FileMode) (*os.File, error) {
pa := getPerms(perms)
fn := RealPath(file)
fp := filepath.Dir(fn)
if !Exists(fn) {
if e := os.MkdirAll(fp, pa[1]); e != nil {
//return nil, errs.RaiseError(ErrCreatePath, "Error create path: '"+fp+"': "+e.Error())
return nil, fmt.Errorf("error create path '%s': %v", fp, e)
}
}
f, e := os.OpenFile(fn, flag, pa[0])
if e != nil {
//return nil, errs.RaiseError(ErrFileOpen, "Error create file: '"+fn+"': "+e.Error())
return nil, fmt.Errorf("error create file '%s': %v", fn, e)
}
return f, nil
}
// Скопировать файл
//
// 0.2.7
func Copy(src, dst string) (e error) {
//Открытие файла-источника
fSrc, e := os.OpenFile(src, os.O_RDONLY, 0666)
if e != nil {
return fmt.Errorf("error open source file (%s): %v", src, e)
}
//Открытие файла-приемника
fDst, e := os.OpenFile(dst, os.O_CREATE, 0666)
if e != nil {
return fmt.Errorf("error open destination file (%s): %v", dst, e)
}
if _, e := io.Copy(fDst, fSrc); e != nil {
return fmt.Errorf("error copy file %s -> %s: %v", src, dst, e)
}
return nil
}