- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个大的文本日志文件,其中包含两部分,并用一些特殊字符分隔,就像
...
this is the very large
part, contains lots lines.
#SPECIAL CHARS START#
...
this is the small part the the end,
contain several lines, but
we do not know how many lines
this part contains
#SPECIAL CHARS START#
之后到最后的一小部分文本内容,如何使用Golang有效地获得它?
func getBackwardLine(file *os.File, start int64) (string, int64) {
line := ""
cursor :=start
stat, _ := file.Stat()
filesize := stat.Size()
for {
cursor--
file.Seek(cursor, io.SeekEnd)
char := make([]byte, 1)
file.Read(char)
if cursor != -1 && (char[0] == 10 || char[0] == 13) {
break
}
line = fmt.Sprintf("%s%s", string(char), line)
if cursor == -filesize {
break
}
}
return line, cursor
}
func main() {
file, err := os.Open("some.log")
if err != nil {
os.Exit(1)
}
defer file.Close()
var cursor int64 = 0
var line = ""
for {
line, cursor = getBackwardLine(file, cursor)
fmt.Println(line)
if(strings.Contains(line, "#SPECIAL CHARS START#")) {
break
}
}
fmt.Println(cursor) //now we get the cursor for the start of special characters
}
最佳答案
该解决方案实现了向后阅读器。
它从头开始按b.Len
字节块读取文件,然后向前寻找一个分隔符,当前为该块内的\n
,然后以SepIndex
推进起始偏移量(这是为了防止将搜索字符串分成两个连续的字符串读)。在进行下一个块读取之前,它将在读取的块中查找search
字符串,如果找到,它将返回其在文件中的起始位置并停止。
否则,它将通过b.Len
减小起始偏移量,然后读取下一个块。
只要您的搜索字符串位于文件的最后40%,您就应该获得更好的性能,,但则需要进行实战测试。
如果您的搜索字符串在最后10%以内,我相信您会赢。
main.go
package main
import (
"bytes"
"flag"
"fmt"
"io"
"log"
"os"
"time"
"github.com/mattetti/filebuffer"
)
func main() {
var search string
var sep string
var verbose bool
flag.StringVar(&search, "search", "findme", "search word")
flag.StringVar(&sep, "sep", "\n", "separator for the search detection")
flag.BoolVar(&verbose, "v", false, "verbosity")
flag.Parse()
d := make(chan struct{})
b := &bytes.Buffer{}
go func() {
io.Copy(b, os.Stdin)
d <- struct{}{}
}()
<-time.After(time.Millisecond)
select {
case <-d:
default:
os.Stdin.Close()
}
readSize := 1024
if b.Len() < 1 {
input := fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), readSize-5), search)
input += input
b.WriteString(input)
}
bsearch := []byte(search)
s, err := bytesSearch(b.Bytes())
if err != nil {
log.Fatal(err)
}
if verbose {
s.logger = log.New(os.Stderr, "", log.LstdFlags)
}
s.Buffer = make([]byte, readSize)
s.Sep = []byte(sep)
got, err := s.Index(bsearch)
if err != nil {
log.Fatal(err)
}
fmt.Println("Index ", got)
got, err = s.Index2(bsearch)
if err != nil {
log.Fatal(err)
}
fmt.Println("Index ", got)
}
type tailSearch struct {
F io.ReadSeeker
Buffer []byte
Sep []byte
start int64
logger interface {
Println(...interface{})
}
}
func fileSearch(f *os.File) (ret tailSearch, err error) {
ret.F = f
st, err := f.Stat()
if err != nil {
return
}
ret.start = st.Size()
ret.Sep = []byte("\n")
return ret, nil
}
func bytesSearch(b []byte) (ret tailSearch, err error) {
ret.F = filebuffer.New(b)
ret.start = int64(len(b))
ret.Sep = []byte("\n")
return
}
func (b tailSearch) Index(search []byte) (int64, error) {
if b.Buffer == nil {
b.Buffer = make([]byte, 1024, 1024)
}
buf := b.Buffer
blen := len(b.Buffer)
hasended := false
for !hasended {
if b.logger != nil {
b.logger.Println("a start", b.start)
}
offset := b.start - int64(blen)
if offset < 0 {
offset = 0
hasended = true
}
_, err := b.F.Seek(offset, 0)
if err != nil {
hasended = true
}
n, err := b.F.Read(buf)
if b.logger != nil {
b.logger.Println("f n", n, "err", err)
}
if err != nil {
hasended = true
}
buf = buf[:n]
b.start -= int64(n)
if b.logger != nil {
b.logger.Println("g start", b.start)
}
if b.start > 0 {
i := bytes.Index(buf, b.Sep)
if b.logger != nil {
b.logger.Println("h sep", i)
}
if i > -1 {
b.start += int64(i)
buf = buf[i:]
if b.logger != nil {
b.logger.Println("i start", b.start)
}
}
}
if e := bytes.LastIndex(buf, search); e > -1 {
return b.start + int64(e), nil
}
}
return -1, nil
}
func (b tailSearch) Index2(search []byte) (int64, error) {
if b.Buffer == nil {
b.Buffer = make([]byte, 1024, 1024)
}
buf := b.Buffer
blen := len(b.Buffer)
hasended := false
for !hasended {
if b.logger != nil {
b.logger.Println("a start", b.start)
}
offset := b.start - int64(blen)
if offset < 0 {
offset = 0
hasended = true
}
_, err := b.F.Seek(offset, 0)
if err != nil {
hasended = true
}
n, err := b.F.Read(buf)
if b.logger != nil {
b.logger.Println("f n", n, "err", err)
}
if err != nil {
hasended = true
}
buf = buf[:n]
b.start -= int64(n)
if b.logger != nil {
b.logger.Println("g start", b.start)
}
for i := 1; i < len(search); i++ {
if bytes.HasPrefix(buf, search[i:]) {
e := i - len(search)
b.start += int64(e)
buf = buf[e:]
}
}
if b.logger != nil {
b.logger.Println("g start", b.start)
}
if e := bytes.LastIndex(buf, search); e > -1 {
return b.start + int64(e), nil
}
}
return -1, nil
}
package main
import (
"bytes"
"fmt"
"strings"
"testing"
)
func TestOne(t *testing.T) {
type test struct {
search []byte
readLen int
input string
sep []byte
want int64
}
search := []byte("find me")
blockLen := 1024
tests := []test{
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf("%stail content", search),
want: 0,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf(""),
want: -1,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: strings.Repeat("nop\n", 10000),
want: -1,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), blockLen-5), search),
want: 1019,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), blockLen), search),
want: 1024,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), blockLen+10), search),
want: 1034,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), (blockLen*2)+10), search),
want: 2058,
},
test{
search: search,
sep: []byte("\n"),
readLen: blockLen,
input: fmt.Sprintf("%s%s%stail content", bytes.Repeat([]byte(" "), (blockLen*2)+10), search, search),
want: 2065,
},
}
for i, test := range tests {
s, err := bytesSearch([]byte(test.input))
if err != nil {
t.Fatal(err)
}
s.Buffer = make([]byte, test.readLen)
s.Sep = test.sep
got, err := s.Index(test.search)
if err != nil {
t.Fatal(err)
}
if got != test.want {
t.Fatalf("invalid index at %v got %v wanted %v", i, got, test.want)
}
got, err = s.Index2(test.search)
if err != nil {
t.Fatal(err)
}
if got != test.want {
t.Fatalf("invalid index at %v got %v wanted %v", i, got, test.want)
}
}
}
package main
import (
"bytes"
"fmt"
"testing"
"github.com/mattetti/filebuffer"
)
func BenchmarkIndex(b *testing.B) {
search := []byte("find me")
blockLen := 1024
input := fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), blockLen-5), search)
input += input
s := tailSearch{}
s.F = filebuffer.New([]byte(input))
s.Buffer = make([]byte, blockLen)
for i := 0; i < b.N; i++ {
s.start = int64(len(input))
_, err := s.Index(search)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkIndex2(b *testing.B) {
search := []byte("find me")
blockLen := 1024
input := fmt.Sprintf("%s%stail content", bytes.Repeat([]byte(" "), blockLen-5), search)
input += input
s := tailSearch{}
s.F = filebuffer.New([]byte(input))
s.Buffer = make([]byte, blockLen)
for i := 0; i < b.N; i++ {
s.start = int64(len(input))
_, err := s.Index2(search)
if err != nil {
b.Fatal(err)
}
}
}
$ go test -v
=== RUN TestOne
--- PASS: TestOne (0.00s)
PASS
ok test/backwardsearch 0.002s
$ go test -bench=. -benchmem -v
=== RUN TestOne
--- PASS: TestOne (0.00s)
goos: linux
goarch: amd64
pkg: test/backwardsearch
BenchmarkIndex-4 20000000 108 ns/op 0 B/op 0 allocs/op
BenchmarkIndex2-4 10000000 167 ns/op 0 B/op 0 allocs/op
PASS
ok test/backwardsearch 4.129s
$ echo "rrrrfindme" | go run main.go -v
2019/10/17 12:17:04 a start 11
2019/10/17 12:17:04 f n 11 err <nil>
2019/10/17 12:17:04 g start 0
Index 4
2019/10/17 12:17:04 a start 11
2019/10/17 12:17:04 f n 11 err <nil>
2019/10/17 12:17:04 g start 0
2019/10/17 12:17:04 g start 0
Index 4
$ cat bench_test.go | go run main.go -search main
Index 8
Index 8
$ go run main.go
Index 2056
Index 2056
关于go - 使用Golang从文本文件末尾读取特定内容的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58407633/
我正在更改链接网址以添加 www.site.com/index.html?s=234&dc=65828 我通过此代码得到的是:site.com/&dc=65828 var target="&dc=65
我在编译过程中收到错误: src/smtp.c:208:1: warning: control reaches end of non-void function [-Wreturn-type] 这是相
这是我的 bootstrap/html 代码: Put email 位置正确,但我希望输入字段的大小延伸到 div 末尾。谁能帮帮我? 最佳答案 只需按百分比指定宽度,如下所示
我正在尝试获取一个像这样的 json 对象: filters = {"filters": myArray}; 并将其附加到 URL 的末尾,使用: this.router.navigate([`/de
这个问题已经有答案了: Remove hash from url (5 个回答) 已关闭 10 年前。 我有一个网站,stepaheadresidents.com ,并且井号 (#) 会自动添加到 u
我有这个代码 $('container a').appendTo('.container'); dzedzdqdqdqzdqdzqdzqdqzdqd Forgot password
为了练习更多 Python 知识,我尝试了 pythonchallenge.com 上的挑战 简而言之,作为第一步,此挑战要求从末尾带有数字的 url 加载 html 页面。该页面包含一行文本,其中有
我对 FS2 很陌生,需要一些有关设计的帮助。我正在尝试设计一个流,它将从底层的 InputStream 中提取 block ,直到结束。这是我尝试过的: import java.io.{File,
我对 FS2 很陌生,需要一些有关设计的帮助。我正在尝试设计一个流,它将从底层的 InputStream 中提取 block ,直到结束。这是我尝试过的: import java.io.{File,
我正在编写一个 ajax 应用程序,并且在 php 脚本中有一个函数: public function expire_user() { $r=array("return"=>'OK');
我正在使用一个QListView,它包装了一个非常简单的列表模型。我想尝试实现类似于某些网页中看到的“无限滚动”的东西。 目前,模型通过最多添加 100 个项目的方法更新(它们取自外部 Web API
运行 cucumber 测试给我以下错误 end of file reached (EOFError) /usr/lib64/ruby/2.0.0/net/protocol.rb:153:in
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我想知道版本命名的具体作用是什么? 喜欢 jquery.js?ver=1.4.4 我的意思是如果我使用像这样的 cdn jquery/1.4.4/jquery.min.js?ver=1.4.4但是另一
" data-fancybox-group="gallery" title="">" alt="" /> 在此代码中 echo $prod['item_image_url'];打印存储在我的表中的图像
我目前使用 Wordpress 作为博客平台,但我想更改为使用 Jekyll 来生成静态页面。在 WordPress 上,我的 URL 使用以下格式: /年/月/日/标题 但我想将其重定向到 /年/月
根据docs这应该是不可能的 Regular expressions cannot be anchored to the beginning or end of a token 尽管如此,它似乎对我有
有没有办法创建 dijit 并将其附加到 div 的末尾?假设我有以下代码: Add Person 我在网上找到了以下代码,但这替换了我的“attendants”div: var personCo
我有这段代码: //execute post (the result will be something like {"result":1,"error":"","id":"4da775
我需要一些函数方面的帮助。 我想编写一个插入链表的函数。但不仅仅是中间,如果必须插入前端或末尾,它也必须起作用。 结构: typedef struct ranklist { i
我是一名优秀的程序员,十分优秀!