.例如 1.日志文件
当我从头读取文件时,我能够得到 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 位置获取线路的位置,我认为这会更有效率。
最佳答案
注意:我优化和改进了以下解决方案,并将其作为库发布在这里:github.com/icza/backscanner
bufio.Scanner使用 io.Reader作为其来源,它不支持从任意位置查找和/或读取,因此它无法从末尾扫描行。 bufio.Scanner 只能在输入的所有数据都已被读取后才能读取输入的任何部分(也就是说,如果它首先读取了文件的所有内容,它只能读取文件的末尾)。
所以我们需要一个定制的解决方案来实现这样的功能。还好os.File确实支持从任意位置读取,因为它实现了 io.Seeker和 io.ReaderAt (它们中的任何一个都足以满足我们的需要)。
让我们构建一个 Scanner,它从最后一行开始向后扫描行。为此,我们将使用 io.ReaderAt。以下实现使用一个内部缓冲区,从输入的末尾开始,将数据按 block 读取到该缓冲区中。输入的大小也必须传递(这基本上是我们要开始读取的位置,不一定是结束位置)。
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`
输出(在 Go Playground 上尝试):
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
注意事项:
Scanner 不限制行的最大长度,它处理所有行。Scanner 处理 \n 和 \r\n 行尾(由 dropCR()功能)。Scanner 不重用缓冲区,总是在需要时创建新缓冲区。 (预)分配 2 个缓冲区并明智地使用它们就足够了。实现会变得更加复杂,并且会引入最大行长度限制。要对文件使用此扫描仪,您可以使用os.Open() 打开文件。请注意,*File 实现了 io.ReaderAt()。那么你可以使用 File.Stat()获取有关文件 ( 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() 检查每一行中的子字符串,它返回行内的子字符串位置,如果找到,则将行开始位置添加到此。
假设我们正在寻找 "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
}
}
输出(在 Go Playground 上尝试):
Line start: 24, line: End
Line start: 18, line: Line3
Line start: 12, line: Line2
Found "ine2" at line position: 1, global position: 13
关于file - 从末尾读取日志文件并获取特定字符串的偏移量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46764241/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚