"bytes"
"errors"
"io"
+ "io/fs"
"os"
"path/filepath"
"strings"
if i := bytes.Index(tmpArea[:n], []byte{separation}); i != -1 {
if n-i-1 != 0 {
- t.file.Seek(-int64(n-i-1), 1)
+ t.file.Seek(-int64(n-i-1), int(AtCurrent))
}
if i != 0 {
data = append(data, tmpArea[:i]...)
return
}
-// Seek sets the offset for the next Read or Write on file to offset, interpreted according to whence: 0 means relative to the origin of the file, 1 means relative to the current offset, and 2 means relative to the end. It returns the new offset and an error, if any. The behavior of Seek on a file opened with O_APPEND is not specified.
-func (t *File) Seed(index int64, whence int) (e error) {
+type FileWhence int
+
+const (
+ AtOrigin FileWhence = iota
+ AtCurrent
+ AtEnd
+)
+
+// Seek sets the offset for the next Read or Write on file to offset
+func (t *File) Seed(index int64, whence FileWhence) (e error) {
t.getRWCloser()
if t.Config.AutoClose {
defer t.Close()
}
defer t.l.Unlock()
- t.cu, e = t.file.Seek(index, whence)
+ t.cu, e = t.file.Seek(index, int(whence))
return nil
}
return t.file.Sync()
}
-func (t *File) Create() {
- t.getRWCloser()
+func (t *File) Create(mode ...fs.FileMode) {
+ t.getRWCloser(mode...)
if t.Config.AutoClose {
defer t.Close()
}
}
func (t *File) IsExist() bool {
- if len(t.Config.FilePath) > 4096 {
- panic(ErrFilePathTooLong)
+ _, err := t.Stat()
+ if errors.Is(err, ErrFilePathTooLong) {
+ panic(err)
}
+ return err == nil
+}
- _, err := os.Stat(t.Config.FilePath)
+func (t *File) IsDir() bool {
+ info, err := t.Stat()
if err != nil {
- if errors.Is(err, os.ErrNotExist) {
- return false
- } else {
- if !strings.Contains(err.Error(), "file name too long") {
- panic(ErrFilePathTooLong)
- }
- return false
- }
+ panic(err)
}
- return true
+ return info.IsDir()
}
-func (t *File) IsDir() bool {
+func (t *File) File() *os.File {
+ t.getRWCloser()
+ return t.file
+}
+
+func (t *File) Stat() (fs.FileInfo, error) {
if len(t.Config.FilePath) > 4096 {
- panic(ErrFilePathTooLong)
+ return nil, ErrFilePathTooLong
}
info, err := os.Stat(t.Config.FilePath)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
- return false
+ return nil, os.ErrNotExist
} else {
if !strings.Contains(err.Error(), "file name too long") {
- panic(ErrFilePathTooLong)
+ return nil, ErrFilePathTooLong
}
- return false
+ return nil, err
}
}
- return info.IsDir()
-}
-
-func (t *File) File() *os.File {
- t.getRWCloser()
- return t.file
+ return info, nil
}
-func (t *File) getRWCloser() {
+func (t *File) getRWCloser(mode ...fs.FileMode) {
+ fmode := fs.ModePerm
+ if len(mode) != 0 {
+ fmode = mode[0]
+ }
if t.Config.AutoClose || t.file == nil {
if !t.IsExist() {
- if e := t.newPath(); e != nil {
- panic(e)
- }
- if f, e := os.Create(t.Config.FilePath); e != nil {
+ newPath(t.Config.FilePath, fs.ModeDir|fmode)
+ if f, e := os.OpenFile(t.Config.FilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fmode); e != nil {
panic(e)
} else {
if t.Config.CurIndex > 0 {
t.cu = t.Config.CurIndex
- t.cu, e = f.Seek(t.cu, 0)
+ t.cu, e = f.Seek(t.cu, int(AtOrigin))
if e != nil {
panic(e)
}
t.file = f
}
} else {
- if f, e := os.OpenFile(t.Config.FilePath, os.O_RDWR|os.O_EXCL, 0644); e != nil {
+ if f, e := os.OpenFile(t.Config.FilePath, os.O_RDWR|os.O_EXCL, fmode); e != nil {
panic(e)
} else {
if t.Config.CurIndex != 0 {
t.cu = t.Config.CurIndex
- whenc := 0
+ whenc := AtOrigin
if t.Config.CurIndex < 0 {
t.cu = t.cu + 1
- whenc = 2
+ whenc = AtEnd
}
- t.cu, e = f.Seek(t.cu, whenc)
+ t.cu, e = f.Seek(t.cu, int(whenc))
if e != nil {
panic(e)
}
}
}
-func (t *File) newPath() error {
+func newPath(path string, mode fs.FileMode) {
rawPath := ""
- if !filepath.IsAbs(t.Config.FilePath) {
+ if !filepath.IsAbs(path) {
rawPath, _ = os.Getwd()
}
- rawPs := strings.Split(t.Config.FilePath, string(os.PathSeparator))
+ rawPs := strings.Split(path, string(os.PathSeparator))
for n, p := range rawPs {
if p == "" || p == "." {
continue
break
}
rawPath += string(os.PathSeparator) + p
-
if _, err := os.Stat(rawPath); os.IsNotExist(err) {
- err := os.Mkdir(rawPath, os.ModePerm)
- if err != nil {
- return err
- }
+ os.Mkdir(rawPath, mode)
}
}
-
- return nil
}
func transferIO(r io.Reader, w io.Writer, byteInSec int64) (e error) {
"bytes"
"errors"
"io"
+ "os"
"runtime"
"testing"
+ "time"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/unicode"
)
func TestNewPath2(t *testing.T) {
- {
- f := New("./test/test.log", 0, true)
- f.Create()
- if !f.IsExist() {
- t.Fatal()
- }
- f.Delete()
- }
- {
- f := New("./test/test.log", 0, true)
- f.Create()
- f.Delete()
- }
+ os.RemoveAll("./test")
+ time.Sleep(time.Second)
+ go New("./test/test.log", 0, true).Create()
+ go New("./test/test2.log", 0, true).Create()
+ time.Sleep(time.Second)
}
func TestNewPath(t *testing.T) {
t.Fatal(e)
}
- if e := f.Seed(0, 0); e != nil {
+ if e := f.Seed(0, AtOrigin); e != nil {
t.Fatal(e)
}
t.Fatal(e)
}
- if e := f.Seed(1, 0); e != nil {
+ if e := f.Seed(1, AtOrigin); e != nil {
t.Fatal(e)
}
}
}
- if e := f.Seed(-1, 2); e != nil {
+ if e := f.Seed(-1, AtEnd); e != nil {
t.Fatal(e)
}
t.Fatal(e)
}
- if e := f.Seed(0, 0); e != nil {
+ if e := f.Seed(0, AtOrigin); e != nil {
t.Fatal(e)
}