file/filetools.go

222 lines
5.5 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/ioutil"
"os"
"os/user"
"path/filepath"
"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 {
if len(path) < 1 {
return GetCWD()
}
switch path[0] {
case '.':
return GetBinDir() + "/" + strings.TrimLeft(path, "./")
case '~':
return GetHome() + "/" + strings.TrimLeft(path, "~/")
case '/':
return path
default:
return GetCWD() + "/" + path
}
}
//Получить расширение файла
// 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(file) {
//return nil, errs.RaiseError(ErrFileNotFound, "File '"+file+"' not found")
return nil, fmt.Errorf("file not found: %s", file)
}
ret, e := ioutil.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
}
//Сохранить файл, создать путь если не существует
// 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
}
//Разобрать массив прав
// 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(); err != 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
}
//Сохранить 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.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.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
}