ErrFailToLock = errors.New("ErrFailToLock")
ErrMaxReadSizeReach = errors.New("ErrMaxReadSizeReach")
ErrNoDir = errors.New("ErrNoDir")
+ ErrArg = errors.New("ErrArg")
)
type File struct {
return t.read().Read(data)
}
-func (t *File) ReadUntil(separation byte, perReadSize int, maxReadSize int) (data []byte, e error) {
+// stop after untilBytes
+//
+// data not include untilBytes
+func (t *File) ReadUntil(untilBytes []byte, perReadSize int, maxReadSize int) (data []byte, e error) {
t.getRWCloser()
if t.Config.AutoClose {
defer t.Close()
defer t.l.RUnlock()
var (
- tmpArea = make([]byte, perReadSize)
+ reserve = len(untilBytes) - 1
+ tmpArea = make([]byte, reserve+perReadSize)
n int
reader = t.read()
)
- for maxReadSize > 0 {
+ {
+ var seekN int
+ if reserve != 0 {
+ //avoid spik
+ if _, e := t.file.Seek(-int64(reserve), int(AtCurrent)); e == nil {
+ seekN = reserve
+ }
+ }
n, e = reader.Read(tmpArea)
+ if n == 0 && e != nil {
+ return
+ }
+
+ maxReadSize = maxReadSize - n
+
+ if i := bytes.Index(tmpArea[:n], untilBytes); i != -1 {
+ if n-i-len(untilBytes) != 0 {
+ _, _ = t.file.Seek(-int64(n-i-len(untilBytes)), int(AtCurrent))
+ }
+ if i != 0 {
+ data = append(data, tmpArea[seekN:i]...)
+ }
+ return
+ } else {
+ data = append(data, tmpArea[seekN:n]...)
+ }
+ }
+
+ for maxReadSize > 0 {
+ if reserve != 0 {
+ copy(tmpArea, tmpArea[reserve:])
+ }
+ n, e = reader.Read(tmpArea[reserve:])
if n == 0 && e != nil {
return
maxReadSize = maxReadSize - n
- if i := bytes.Index(tmpArea[:n], []byte{separation}); i != -1 {
- if n-i-1 != 0 {
- t.file.Seek(-int64(n-i-1), int(AtCurrent))
+ if i := bytes.Index(tmpArea[:reserve+n], untilBytes); i != -1 {
+ if reserve+n-i-len(untilBytes) != 0 {
+ _, _ = t.file.Seek(-int64(reserve+n-i-len(untilBytes)), int(AtCurrent))
}
if i != 0 {
- data = append(data, tmpArea[:i]...)
+ data = append(data, tmpArea[reserve:i]...)
}
break
} else {
- data = append(data, tmpArea[:n]...)
+ data = append(data, tmpArea[reserve:n]...)
}
}
var (
tmpArea = make([]byte, perReadSize)
- n = 0
+ n int
reader = t.read()
)
}
maxReadSize = maxReadSize - n
-
data = append(data, tmpArea[:n]...)
}
)
// Seek sets the offset for the next Read or Write on file to offset
-func (t *File) Seed(index int64, whence FileWhence) (e error) {
+func (t *File) SeekIndex(index int64, whence FileWhence) (e error) {
t.getRWCloser()
if t.Config.AutoClose {
defer t.Close()
t.cu, e = t.file.Seek(index, int(whence))
- return nil
+ return
+}
+
+// stop before untilBytes
+func (t *File) SeekUntil(untilBytes []byte, whence FileWhence, perReadSize int, maxReadSize int) (e error) {
+ t.getRWCloser()
+ if t.Config.AutoClose {
+ defer t.Close()
+ }
+
+ if !t.l.TryRLock() {
+ return ErrFailToLock
+ }
+ defer t.l.RUnlock()
+
+ var (
+ reserve = len(untilBytes) - 1
+ tmpArea = make([]byte, reserve+perReadSize)
+ n int
+ reader = t.read()
+ )
+
+ if reserve != 0 {
+ //avoid spik
+ _, _ = t.file.Seek(-int64(reserve), int(AtCurrent))
+ }
+
+ {
+ n, e = reader.Read(tmpArea)
+ if n == 0 && e != nil {
+ return
+ }
+
+ maxReadSize = maxReadSize - n
+
+ if i := bytes.Index(tmpArea[:n], untilBytes); i != -1 {
+ if n-i != 0 {
+ _, _ = t.file.Seek(-int64(n-i), int(AtCurrent))
+ }
+ return
+ }
+ }
+
+ for maxReadSize > 0 {
+ if reserve != 0 {
+ copy(tmpArea, tmpArea[reserve:])
+ }
+ n, e = reader.Read(tmpArea[reserve:])
+ if n == 0 && e != nil {
+ return
+ }
+
+ maxReadSize = maxReadSize - n
+
+ if i := bytes.Index(tmpArea[:reserve+n], untilBytes); i != -1 {
+ if reserve+n-i != 0 {
+ _, _ = t.file.Seek(-int64(reserve+n-i), int(AtCurrent))
+ }
+ break
+ }
+ }
+
+ if maxReadSize <= 0 {
+ e = ErrMaxReadSizeReach
+ }
+
+ return
}
func (t *File) Sync() (e error) {
}
rawPath += string(os.PathSeparator) + p
if _, err := os.Stat(rawPath); os.IsNotExist(err) {
- os.Mkdir(rawPath, mode)
+ _ = os.Mkdir(rawPath, mode)
}
}
}
t.Fatal(e)
}
- if e := f.Seed(0, AtOrigin); e != nil {
+ if e := f.SeekIndex(0, AtOrigin); e != nil {
t.Fatal(e)
}
}
}
-func TestSeed(t *testing.T) {
+func TestSeek(t *testing.T) {
f := New("rwd.txt", 0, false)
if i, e := f.Write([]byte("12er4x3"), true); i == 0 || e != nil {
t.Fatal(e)
}
- if e := f.Seed(1, AtOrigin); e != nil {
+ if e := f.SeekIndex(1, AtOrigin); e != nil {
t.Fatal(e)
}
}
}
- if e := f.Seed(-1, AtEnd); e != nil {
+ if e := f.SeekIndex(-1, AtEnd); e != nil {
t.Fatal(e)
}
}
}
+func TestSeek2(t *testing.T) {
+ f := New("rwd.txt", 0, false)
+ if f.IsExist() {
+ if e := f.Delete(); e != nil {
+ t.Fatal(e)
+ }
+ }
+ if i, e := f.Write([]byte("12345sser4x3"), true); i == 0 || e != nil {
+ t.Fatal(e)
+ }
+
+ f.SeekIndex(0, AtOrigin)
+
+ if e := f.SeekUntil([]byte("sser"), AtCurrent, 3, 1<<20); e != nil && !errors.Is(e, io.EOF) {
+ t.Fatal(e)
+ }
+
+ if data, e := f.ReadAll(5, 1<<20); e != nil && !errors.Is(e, io.EOF) {
+ t.Fatal(e)
+ } else if !bytes.Equal(data, []byte("sser4x3")) {
+ t.Fatal(string(data), data)
+ }
+
+ if e := f.Close(); e != nil {
+ t.Fatal(e)
+ }
+
+ if e := f.Delete(); e != nil {
+ t.Fatal(e)
+ }
+}
+
+func TestSeek3(t *testing.T) {
+ f := New("0.mp4", 0, false)
+ defer f.Close()
+ var boxBuf = make([]byte, 4)
+ if e := f.SeekUntil([]byte("mvhd"), AtCurrent, 1<<17, 1<<22); e != nil && !errors.Is(e, ErrMaxReadSizeReach) {
+ t.Fatal(e)
+ }
+ if _, e := f.Read(boxBuf); e != nil {
+ t.Fatal(e)
+ } else if !bytes.Equal(boxBuf, []byte("mvhd")) {
+ t.Fatalf("wrong box:%v", string(boxBuf))
+ }
+}
+
func TestCopy(t *testing.T) {
sf := New("s.txt", 0, true)
if i, e := sf.Write([]byte("12er4x3"), true); i == 0 || e != nil {
func TestReadUntil(t *testing.T) {
f := New("s.txt", 0, false)
- if i, e := f.Write([]byte("18u3y7\ns99s9\n"), true); i == 0 || e != nil {
+ if i, e := f.Write([]byte("18u3y7\ns99s9\nuqienbs\n"), true); i == 0 || e != nil {
t.Fatal(e)
}
t.Fatal(e)
}
- if e := f.Seed(0, AtOrigin); e != nil {
+ if e := f.SeekIndex(0, AtOrigin); e != nil {
t.Fatal(e)
}
- if data, e := f.ReadUntil('\n', 5, 20); e != nil {
+ if data, e := f.ReadUntil([]byte{'\n'}, 5, 20); e != nil {
t.Fatal(e)
} else if !bytes.Equal(data, []byte("18u3y7")) {
t.Fatal(string(data))
}
- if data, e := f.ReadUntil('\n', 5, 20); e != nil {
+ if data, e := f.ReadUntil([]byte{'\n'}, 5, 20); e != nil {
t.Fatal(e)
} else if !bytes.Equal(data, []byte("s99s9")) {
t.Fatal(string(data))
}
- if data, e := f.ReadUntil('\n', 5, 20); e == nil || !errors.Is(e, io.EOF) || len(data) != 0 {
+ if data, e := f.ReadUntil([]byte("s\n"), 5, 20); e != nil {
+ t.Fatal(e)
+ } else if !bytes.Equal(data, []byte("uqienb")) {
+ t.Fatal(string(data))
+ }
+
+ if data, e := f.ReadUntil([]byte{'\n'}, 5, 20); e == nil || !errors.Is(e, io.EOF) || len(data) != 0 {
t.Fatal(e)
}
t.Fatal(e)
}
- if data, e := tf.ReadUntil('\n', 3, 100); e != nil && !errors.Is(e, io.EOF) {
+ if data, e := tf.ReadUntil([]byte{'\n'}, 3, 100); e != nil && !errors.Is(e, io.EOF) {
t.Fatal(string(data), e)
} else if !bytes.Equal(data, []byte("测1试s啊是3大家看s法$和")) {
t.Fatal(string(data))
if c.MaxLoop == 0 {
if c.MaxByte != 0 {
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
}
} else {
if c.MaxByte != 0 {
c.MaxByte = min(c.MaxByte, c.MaxLoop*c.BytePerLoop)
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
}
}
} else if c.BytePerLoop > 1<<17 {
if c.MaxByte != 0 {
c.BytePerLoop = 1 << 17
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
} else {
c.BytePerLoop = 1 << 17
}
c.MaxByte = min(c.MaxByte, c.MaxLoop*c.BytePerLoop)
c.BytePerLoop = 1 << 17
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
} else {
c.MaxByte = c.MaxLoop * c.BytePerLoop
c.BytePerLoop = 1 << 17
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
}
}
} else {
if c.MaxLoop == 0 {
if c.MaxByte != 0 {
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
}
} else {
if c.MaxByte != 0 {
c.MaxByte = min(c.MaxByte, c.MaxLoop*c.BytePerLoop)
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
} else {
c.MaxByte = c.MaxLoop * c.BytePerLoop
leftN = c.MaxByte % c.BytePerLoop
- c.MaxLoop = c.MaxByte/c.BytePerLoop + 1
+ c.MaxLoop = c.MaxByte / c.BytePerLoop
+ if leftN > 0 {
+ c.MaxLoop += 1
+ }
}
}
}
if c.MaxLoop > 0 {
c.MaxLoop -= 1
- if c.MaxLoop == 0 {
- return nil
- } else if c.BytePerLoop == 1<<17 && leftN != 0 {
+ if c.MaxLoop == 1 && leftN != 0 {
buf = buf[:leftN]
+ } else if c.MaxLoop == 0 {
+ return nil
}
}
if c.BytePerSec != 0 && readC >= c.BytePerSec {
for sg.Islive() {
if data == nil {
- if data, e = f.ReadUntil('\n', 70, humanize.MByte); e != nil && !errors.Is(e, io.EOF) {
+ if data, e = f.ReadUntil([]byte{'\n'}, 70, humanize.MByte); e != nil && !errors.Is(e, io.EOF) {
panic(e)
}
if len(data) == 0 {