从末尾读取日志文件并获取特定字符串的偏移量

2023-12-25

。例如。 1.logfile

  • Start
  • Line1
  • Line2
  • Line3
  • End

当我从头读取文件时,我能够得到 Line1 的查找位置。

func getSeekLocation() int64 {
    start := int64(0)
    input, err := os.Open(logFile)
    if err != nil {
        fmt.Println(err)
    }
    if _, err := input.Seek(start, io.SeekStart); err != nil {
        fmt.Println(err)
    }
    scanner := bufio.NewScanner(input)

    pos := start
    scanLines := func(data []byte, atEOF bool) (advance int, token []byte, 
    err error) {
        advance, token, err = bufio.ScanLines(data, atEOF)
        pos += int64(advance)
        return
    }
    scanner.Split(scanLines)
    for scanner.Scan() {
       if strings.Contains(scanner.Text(), "Line1") {
        break
       }
    }
    size, err := getFileSize()
    if err != nil {
        fmt.Println(err)
    }
    return size - pos
}

但这并不是解决问题的有效方法,因为随着文件大小的增加,获取位置的时间也会增加。 我想从 EOF 位置获取线路的位置,我认为这会更有效。


Note:我优化和改进了以下解决方案,并将其作为库发布在这里:github.com/icza/backscanner https://github.com/icza/backscanner


bufio.Scanner https://golang.org/pkg/bufio/#Scanner使用一个io.Reader https://golang.org/pkg/io/#Reader作为其源,它不支持从任意位置查找和/或读取,因此它无法从末尾扫描行。bufio.Scanner只有在读取了输入之前的所有数据后,才能读取输入的任何部分(也就是说,如果它首先读取文件的所有内容,则只能读取文件的末尾)。

因此我们需要一个定制的解决方案来实现此类功能。幸运的是os.File https://golang.org/pkg/os/#File确实支持从任意位置读取,因为它实现了io.Seeker https://golang.org/pkg/io/#Seeker and io.ReaderAt https://golang.org/pkg/io/#ReaderAt(其中任何一个都足以满足我们的需要)。

从末尾开始向后返回行的扫描仪

让我们构建一个Scanner扫描线backward,从最后一行开始。为此,我们将利用io.ReaderAt。以下实现使用内部缓冲区,从输入末尾开始按块读取数据。还必须传递输入的大小(这基本上是我们要开始读取的位置,不一定是结束位置)。

type Scanner struct {
    r   io.ReaderAt
    pos int
    err error
    buf []byte
}

func NewScanner(r io.ReaderAt, pos int) *Scanner {
    return &Scanner{r: r, pos: pos}
}

func (s *Scanner) readMore() {
    if s.pos == 0 {
        s.err = io.EOF
        return
    }
    size := 1024
    if size > s.pos {
        size = s.pos
    }
    s.pos -= size
    buf2 := make([]byte, size, size+len(s.buf))

    // ReadAt attempts to read full buff!
    _, s.err = s.r.ReadAt(buf2, int64(s.pos))
    if s.err == nil {
        s.buf = append(buf2, s.buf...)
    }
}

func (s *Scanner) Line() (line string, start int, err error) {
    if s.err != nil {
        return "", 0, s.err
    }
    for {
        lineStart := bytes.LastIndexByte(s.buf, '\n')
        if lineStart >= 0 {
            // We have a complete line:
            var line string
            line, s.buf = string(dropCR(s.buf[lineStart+1:])), s.buf[:lineStart]
            return line, s.pos + lineStart + 1, nil
        }
        // Need more data:
        s.readMore()
        if s.err != nil {
            if s.err == io.EOF {
                if len(s.buf) > 0 {
                    return string(dropCR(s.buf)), 0, nil
                }
            }
            return "", 0, s.err
        }
    }
}

// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
    if len(data) > 0 && data[len(data)-1] == '\r' {
        return data[0 : len(data)-1]
    }
    return data
}

使用它的示例:

func main() {
    scanner := NewScanner(strings.NewReader(src), len(src))
    for {
        line, pos, err := scanner.Line()
        if err != nil {
            fmt.Println("Error:", err)
            break
        }
        fmt.Printf("Line start: %2d, line: %s\n", pos, line)
    }
}

const src = `Start
Line1
Line2
Line3
End`

输出(尝试一下去游乐场 https://play.golang.org/p/Wujr0QcL3P):

Line start: 24, line: End
Line start: 18, line: Line3
Line start: 12, line: Line2
Line start:  6, line: Line1
Line start:  0, line: Start
Error: EOF

Notes:

  • 以上Scanner不限制行的最大长度,它可以处理所有行。
  • 以上Scanner处理两者\n and \r\n行结尾(由dropCR()功能)。
  • 您可以传递任何起始位置,而不仅仅是尺寸/长度,列表行将从那里开始执行(继续)。
  • 以上Scanner不重用缓冲区,总是在需要时创建新缓冲区。 (预)分配 2 个缓冲区并明智地使用它们就足够了。实施将变得更加复杂,并且会引入最大线路长度限制。

与文件一起使用

要使用这个Scanner对于文件,您可以使用os.Open()打开一个文件。注意*File实施io.ReaderAt()。那么你可以使用File.Stat() https://golang.org/pkg/os/#File.Stat获取有关文件的信息(os.FileInfo https://golang.org/pkg/os/#FileInfo),包括其尺寸(长度):

f, err := os.Open("a.txt")
if err != nil {
    panic(err)
}
fi, err := f.Stat()
if err != nil {
    panic(err)
}
defer f.Close()

scanner := NewScanner(f, int(fi.Size()))

在一行中寻找子串

如果您正在寻找一行中的子字符串,那么只需使用上面的Scanner它返回每行的起始位置,从末尾读取行。

您可以使用检查每行中的子字符串strings.Index() https://golang.org/pkg/strings/#Index,它返回行内的子字符串位置,如果找到,则将行起始位置添加到此。

假设我们正在寻找"ine2"子字符串(它是"Line2"线)。您可以按照以下方法执行此操作:

scanner := NewScanner(strings.NewReader(src), len(src))
what := "ine2"
for {
    line, pos, err := scanner.Line()
    if err != nil {
        fmt.Println("Error:", err)
        break
    }
    fmt.Printf("Line start: %2d, line: %s\n", pos, line)

    if i := strings.Index(line, what); i >= 0 {
        fmt.Printf("Found %q at line position: %d, global position: %d\n",
            what, i, pos+i)
        break
    }
}

输出(尝试一下去游乐场 https://play.golang.org/p/ixMatyaSMA):

Line start: 24, line: End
Line start: 18, line: Line3
Line start: 12, line: Line2
Found "ine2" at line position: 1, global position: 13
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从末尾读取日志文件并获取特定字符串的偏移量 的相关文章

  • Google Cloud Kubernetes 上任务队列的替代方案

    我发现任务队列主要用于App Engine标准环境 我正在将现有服务从 App Engine 迁移到 Kubernetes 任务队列的一个好的替代方案是什么 推送队列是当前正在使用的队列 我在线阅读文档并浏览了此链接 何时使用 PubSub
  • 无需时间即可生成随机字符串?

    我知道如何使用 Runes 和播种 rand Init 在 go 中生成随机字符串time UnixNano 我的问题是 是否可以 使用 stdlib 在不使用当前时间戳 安全 的情况下播种 rand 此外 我问 因为仅仅依靠时间来为敏感操
  • 移动文件并覆盖[重复]

    这个问题在这里已经有答案了 即使同名文件已存在 我也尝试移动文件 NSFileManager moveItemAtURL location1 toURL location2 Does NSFileManager的方法moveItemAtUR
  • 如何在 Visual Studio Code 中使用 Delve 调试器进行远程调试

    我已经问过了 得到了很好的答复answer https stackoverflow com questions 39058823 how to use delve debugger in visual studio code用于使用 del
  • Go中如何自定义http.Client或http.Transport超时重试?

    我想实现一个自定义http Transport对于标准http Client 如果客户端超时 它将自动重试 附 由于某种原因 习俗http Transport is a 一定有 我已经查过了hashcorp go retryablehttp
  • 构建链代码时 ltdl.h 未找到错误

    我正在尝试使用构建链码go build 当我运行 Go build 命令时它的报告 hyperledger fabric vendor github com miekg pkcs11 pkcs11 g o 29 18 fatal error
  • 当涉及多个渠道时,select 如何工作?

    我发现在多个非缓冲通道上使用 select 时 例如 select case lt chana case lt chanb 即使两个通道都有数据 但在处理此选择时 case chana 和 case chanb 的跟注不平衡 package
  • 用 C 更快地读取文件

    嗯 我想知道是否有一种比使用 fscanf 更快地读取文件的方法 例如假设我有这个文本 4 55 k 52 o 24 l 523 i 首先 我想读取第一个数字 它给出了接下来的行数 令这个数称为N N 之后 我想读取 N 行 其中有一个整数
  • FileReader 在 Ionic 2 中未触发 onloadend

    我正在尝试使用 cordova file plugin 读取本地文件 目前我可以读取本地目录的内容并选择单个文件 但我在获取文件内容时遇到问题 这是我的函数 从列表中选择文件后单击按钮即可调用该函数 import window resolv
  • 如何在 Windows 7 中使用 Python 廉价地创建非常大的文件? [复制]

    这个问题在这里已经有答案了 可能的重复 在Windows系统上快速创建大文件 https stackoverflow com questions 982659 quickly create large file on a windows s
  • 如何重命名 GitHub 网站上的目录/文件夹?

    我在 GitHub 网站上找到了一种方法rename https github com blog 1436 moving and renaming files on github一个文件并成功完成 我也找到了一种方法rename https
  • 为什么 .NET 异步等待文件复制比同步 File.Copy() 调用消耗更多 CPU?

    为什么下面的代码会产生 public static class Program public static void Main params string args var sourceFileName C Users ehoua Desk
  • 修饰符 async 对此项目无效

    这似乎并不是数百个具有相同错误的其他问题的重复 我把它们都看过了 发现它们是无关的 我正在制作一个小笔记应用程序 并尝试从目录中读取文件 按照 MSDN 示例 我有以下代码 但它给了我一个错误 错误 1 修饰符 async 对此无效 项目
  • 并行模拟写入同一文件

    我的目标是在集群上并行运行 10 000 个左右的 Julia 编码模拟 每个模拟独立于所有其他模拟 每个模拟都有一个要输出的数字 以及有关哪个模拟产生该数字的 3 列信息 因此 强制每个模拟打印在单独的文件上对我来说听起来有点愚蠢 我可以
  • 单击一次文件丢失

    将 Clickonce 与 VS 2010 和 NET Framework Client profile 3 5 一起使用 我有几个文件夹 其中包含运行时所需的应用程序级 XML 和 或文本文件 这些文件夹位于要使用它们的同一项目中 这些文
  • PHP将数据写入文件中间而不重写文件的最佳方法是什么

    我正在 php 1GB 中处理大型文本文件 我正在使用 file get contents file txt NULL NULL 100000000 100 要从文件中间获取数据 但如果我想将文件中的数据更改为与原始数据不同的更改 我将不得
  • 鸭子在 Go 中打字

    我想写一个Join函数接受任意对象String 方法 package main import fmt strings type myint int func i myint String string return fmt Sprintf
  • 匿名结构和空结构

    http play golang org p vhaKi5uVmm http play golang org p vhaKi5uVmm package main import fmt var battle make chan string
  • 为什么 Go 禁止取 (&) 映射成员的地址,却允许取 (&) 切片元素?

    Go 不允许获取地图成员的地址 if I do this p mm abc Syntax Error cannot take the address of mm abc 理由是 如果 Go 允许使用此地址 那么当地图后台存储增长或缩小时 该
  • 这两种方式哪一种是惯用的方式? time.Sleep() 还是自动收报机?

    我必须每分钟执行一些语句 我不确定我应该遵循以下哪一项 如果有人能解释内存和 CPU 方面的优缺点 那就太好了 时间 Sleep func main go func for time Sleep time Minute fmt Printl

随机推荐

  • 命令行 Jasypt 客户端加密“无法操作”

    我正在使用 Jasypt 以非明文格式将数据库密码存储在休眠配置文件中 例如代替
  • C++ 模板和 ODR 规则

    为什么以下工作在C 我想ODR规则将出现在以下代码中 typedef char int8 class Sample public template
  • 当用户创建挂载点时如何收到通知?

    首先 这是限制 必须在XP上运行 必须通知驱动器盘符分配以及将卷安装到文件夹 如果驱动器正在睡眠 则不得 唤醒 该驱动器 我真的不想轮询驱动器 我尝试过的 Google 我查看了 WMI 和 Win32 LogicalDisk 类 我可以确
  • Linux 上的 Docker - 清空已安装的卷

    我正在尝试让我的 docker 设置在我的 Linux 机器上运行 它在 OSX 上运行良好 我一生都无法将卷正确安装到 Linux 机器上 我使用的是 Elementary OS 0 4 Loki 64 位 码头工人版本 Client V
  • 如何在 OpenCV 中校正裁剪后的立体图像?

    我有一对水平对齐的立体相机 它们是使用图像的全尺寸进行校准的 我通过调用 cv2 initUn DistorifyMap 来获取每个摄像机的地图进行纠正 然后调用 cv2 remap 使用全尺寸图像时 如下所示 map1 map2 cv2
  • 如何在select2框架中使用占位符作为默认值

    获得a的选定值select2我在用着 var x select select2 data var select choice x text 问题是 如果未选择值 则会引发错误 我想知道如果未选择任何选项 是否有任何方法使其返回占位符 您必须
  • 使用 Mathnet 数字库进行 Svd 重组似乎是错误的

    我正在寻找 Mathnet Iridium 和 Mathnet Numerics 之间的非回归 这是我的代码 使用 Mathnet Numerics double symJaggedArray new double 5 symJaggedA
  • Java方法性能中使用final关键字? [复制]

    这个问题在这里已经有答案了 是否使用final在方法参数中允许编译器或运行时环境更快地工作 例如 如果您有一个变量要传递给一个您知道不会被修改并按原样使用的方法 那么声明它是否更有效final 例子 第一种方法应该比第二种方法更快 publ
  • javascript 函数返回不起作用

    我在函数中返回变量时遇到问题 以下脚本工作正常 function sessionStatus document ready function getJSON scriptRoot sessionStatus php function sta
  • k8s - livenessProbe 与 readinessProbe

    考虑一个通过 http 端点进行健康检查设置的 pod health在端口 80 上 需要近 60 秒才能真正准备好并为流量提供服务 readinessProbe httpGet path health port 80 initialDel
  • Excel VBA - 日期格式自动更改

    我试图通过在 Sheets Sheet1 Cells 17 3 Value 中的日期添加一个月来输入日期值 该值是 01 10 2011 但格式为 Oct 11 然后返回 Sheets Sheet1 Cells 17 4 Value LDa
  • 如何根据分辨率调整控件大小?

    在 WinForms 应用程序中 处理调整控件大小以匹配基于屏幕分辨率以及最大化和调整窗口大小的最佳方法是什么 我有 3 列是这样设置的 每列中的标签文本框 您可以将其算作 6 列 我尝试过锚定到右侧 但问题是第 1 列中的文本框将与接下来
  • 带参数的本地化字符串在参数周围添加换行符和括号

    我正在尝试显示包含参数的本地化字符串 结果不是将嵌入参数的字符串显示在一行中 而是显示一个损坏的 3 行字符串 预期结果 The price is 9 99 year Result The price is 9 99 year 可本地化的字
  • boost::与 boost::asio 结合在一起。 boost::bind 不起作用,从示例复制

    有人能告诉我为什么这不能编译吗 我基本上是从 Kholkoff 的一个例子中复制过来的 http lists boost org Archives boost 2007 04 120339 php http lists boost org
  • 使用matlab求级数求和

    当我在 matlab 中写这个时 syms x f x 3 cos x g diff f 它给出的输出为 g 3 x 2 正弦 x Now I want to generate summation series as 我搜索并找到 syms
  • 如何解码编码字字符串?

    请注意 这个问题与this https stackoverflow com questions 15098452 how can i decode a quotedprintable encoded string以前未回答的问题 它也同样是
  • pyplot:更改图例中的 ncol

    我正在 pyplot 中绘制一个大数据集和一些回归 数据根据附加值着色 我决定将图例中的列数设置为 2 数据点看起来不错 但对于回归 我想回到 ncols 1 有可能在一个图例中做到这一点吗 我知道 我可以宣布两个传奇 但我想避免这种情况
  • 如何安装JDBC以及如何使用它连接mysql?

    我正在尝试安装 JDBC 但我不知道如何 当你只有 jar 文件时 我将其复制到我的 java ext 文件夹 但它一直给我一个错误 任何人都可以告诉我如何完成驱动程序的安装并使用它吗 下面是我使用的代码 import java sql p
  • ANTLR:有一个简单的例子吗?

    我想开始使用 ANTLR 但是在花了几个小时查看了示例之后antlr org http www antlr org 网站上 我仍然无法清楚地了解Java的语法过程 有没有一些简单的例子 比如用 ANTLR 实现的四操作计算器 遍历解析器定义
  • 从末尾读取日志文件并获取特定字符串的偏移量

    例如 1 logfile Start Line1 Line2 Line3 End 当我从头读取文件时 我能够得到 Line1 的查找位置 func getSeekLocation int64 start int64 0 input err