我基本上需要处理从流中读取的有限缓冲区中的每个字符串行。使用 bufio.Scanner,我可以逐行扫描扫描仪,但不得不使用似乎过于复杂的解决方案来检测“截断”。有更好的方法吗?非常感谢。我对任何 lib 或任何东西都不紧张。
func (p *Parser) Read(data []byte, tmpline *string, n int, bufSize int) {
var line string
strdata := string(data)
scanner := bufio.NewScanner(strings.NewReader(strdata))
line = ""
for scanner.Scan() {
if line != "" {
if p.lineProcessor != nil {
p.lineProcessor(line)
}
}
line = scanner.Text()
if *tmpline != "" {
line = *tmpline + line //prepend line here
*tmpline = ""
}
}
if n == bufSize && data[bufSize-1] != '\n' { //detecting a fragment here, overcomplicated?
*tmpline = line
} else {
//fmt.Println("last line >[" + line + "]")
if p.lineProcessor != nil {
p.lineProcessor(line)
}
}
}
func (p *Parser) Handle(r io.Reader, bufSize int) ([]byte, error) {
var out []byte
buf := make([]byte, bufSize)
var n int
var err error
tmpline := ""
for {
n, err = r.Read(buf[:])
if n > 0 {
data := buf[:n]
p.Read(data, &tmpline, n, bufSize)
}
if err != nil {
if err == io.EOF {
err = nil
}
break
}
}
return out, err
}
main
...
cmd := exec.Command("ping", "8.8.8.8")
//var stdout, stderr []byte
var errStdout, errStderr error
//this is the type of stream I want to process **stdoutIn** and **stderrIn**
stdoutIn, _ := cmd.StdoutPipe()
stderrIn, _ := cmd.StderrPipe()
// 10 is the bufSize
parser.Init(stdoutIn, stderrIn, wg, 10, lineProcessor)
...
编辑:我尝试实现建议的解决方案。现在我已经破坏了正在工作的东西(尽管看起来过于复杂)。输出似乎很时髦。这是完整的代码和完整的输出:
package main
import (
"bufio"
"fmt"
"io"
"log"
"os/exec"
"sync"
)
type LineProcessor func(string)
type Parser struct {
r io.Reader
lineProcessor LineProcessor
scanner bufio.Scanner
}
func (p *Parser) Init(stdoutIn io.Reader, stderrIn io.Reader,
wg sync.WaitGroup,
lineProcessor LineProcessor) {
wg.Add(2)
p.lineProcessor = lineProcessor
p.scanner = *bufio.NewScanner(stdoutIn)
go p.Handler(stdoutIn, wg)
go p.Handler(stderrIn, wg)
}
func (p *Parser) Handler(r io.Reader, wg sync.WaitGroup) { // ([]byte, error)
var line string
for p.scanner.Scan() {
line = p.scanner.Text()
if p.lineProcessor != nil {
p.lineProcessor(line)
}
}
wg.Done()
}
func lineProcessor(line string) {
fmt.Println(line)
}
func main() {
var err error
cmd := exec.Command("ping", "8.8.8.8")
var errStdout, errStderr error
stdoutIn, _ := cmd.StdoutPipe()
stderrIn, _ := cmd.StderrPipe()
var parser Parser
var wg sync.WaitGroup
parser.Init(stdoutIn, stderrIn, wg, lineProcessor)
err = cmd.Start()
if err != nil {
log.Fatalf("cmd.Start() failed with '%s'\n", err)
}
fmt.Printf("Waiting\n")
wg.Wait()
err = cmd.Wait()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
if errStdout != nil || errStderr != nil {
log.Fatal("failed to capture stdout or stderr\n")
}
}
$./buggysolution
Waiting
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=52 time=4.786 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=52 time=3.661 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=52 time=4.117 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=52 time=4.172 ms
64 bytes from 8.8.8.8: icmp_seq=8 ttl=52 time=3.584 ms
64 bytes from 8.8.8.8: icmp_seq=10 ttl=52 time=4.301 ms
mp_seq=11 ttl=52 time=4.534 ms
64 bytes from 8.8.8.8: icmp_seq=12 ttl=52 time=4.349 ms
64 bytes from 8.8.8.8: icmp_seq=13 ttl=52 time=4.923 ms
64 bytes from 8.8.8.8: icmp_seq=14 ttl=52 time=4.349 ms
64 bytes from 8.8.8.8: icmp_seq=15 ttl=52 time=4.106 ms
64 bytes from 8.8.8.8: icmp_seq=16 ttl=52 time=4.270 ms
64 bytes from 8.8.8.8: icmp_seq=17 ttl=52 time=4.231 ms
64 bytes from 8.8.8.8: icmp_seq=18 ttl=52 time=4.915 ms
64 bytes from 8.8.8.8: icmp_seq=19 ttl=52 time=4.487 ms
64 bytes from 8.8.8.8: icmp_seq=20 ttl=52 time=4.182 ms
64 bytes from 8.8.8.8: icmp_seq=21 ttl=52 time=4.369 ms
64 bytes from 8.8.8.8: icmp_seq=22 ttl=52 time=4.287 ms
64 bytes from 8.8.8.8: icmp_seq=23 ttl=52 time=3.922 ms
64 bytes from 8.8.8.8: icmp_seq=24 ttl=52 time=4.905 ms
64 bytes from 8.8.8.8: icmp_seq=25 ttl=52 time=4.226 ms
64 bytes from 8.8.8.8: icmp_seq=27 ttl=52 time=4.052 ms
64 bytes from 8.8.8.8: icmp_seq=29 ttl=52 time=3.453 ms
64 bytes from 8.8.8.8: icmp_seq=31 ttl=52 time=5.103 ms
64 bytes from 8.8.8.8: icmp_seq=33 ttl=52 time=4.066 ms
64 bytes from 8.8.8.8: icmp_seq=35 ttl=52 time=4.128 ms
64 bytes from 8.8.8.8: icmp_seq=37 ttl=52 time=4.982 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=52 time=4.206 ms
.64 bytes from 8.8.8.8: icmp_seq=39 ttl=52 time=4.215 ms
.8: icmp_seq=3 ttl=52 time=4.218 ms
tl=52 time=3.650 ms
8: icmp_seq=2 ttl=52 time=3.661 ms
ttl=52 time=4.791 ms
: icmp_seq=5 ttl=52 time=3.581 ms
ttl=52 time=4.211 ms
icmp_seq=4 ttl=52 time=4.117 ms
4 ttl=52 time=4.245 ms
icmp_seq=7 ttl=52 time=4.955 ms
45 ttl=52 time=4.518 ms
cmp_seq=6 ttl=52 time=4.172 ms
=46 ttl=52 time=4.764 ms
seq 9
^C
感谢任何修复。
最佳答案
这不是 bufio.Scanner 的使用方式。
bufio.Scanner 带有一个读取器,可以直接从中返回行。
bufio.Scanner 如果 token 大于 bufio.Scanner.maxTokenSize 将失败,默认情况下是 MaxScanTokenSize 但它不会返回截断的结果。
您还可以在 https://golang.org/src/bufio/scan_test.go#L214 查看测试套件(并不是说所使用的 MaxTokenSize 方法是用特殊方案定义的,仅在测试期间存在,请参阅 https://golang.org/src/bufio/export_test.go#L16)
您还可以在扫描之前定义自己的底层缓冲区以更改该值 https://golang.org/pkg/bufio/#Scanner.Buffer
推出你自己的版本可能看起来像这样https://play.golang.org/p/kDcO6eZPVhY然而,沿着这条路走下去需要您编写额外的测试和基准。
经过多条评论,这里是 OP 正在寻找的内容:
package main
import (
"bufio"
"io"
"log"
"os/exec"
)
func main() {
cmd := exec.Command("ping", "8.8.8.8")
var out io.Reader
{
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
log.Fatal(err)
}
out = io.MultiReader(stdout, stderr)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
// defer cmd.Process.Kill()
s := bufio.NewScanner(out)
for s.Scan() {
log.Println(s.Text())
}
// if out closes, cmd closed.
log.Println("all done")
}
关于go - bufio.扫描仪 : how to know if we are processing a new line or a truncated string?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57938904/
在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol
我想扫描未知数量的行,直到扫描完所有行。我如何在ruby中做到这一点?例如:putreturnsbetweenparagraphsforlinebreakadd2spacesatend_italic_or**bold**输入不是来自"file",而是通过STDIN。 最佳答案 在ruby中有很多方法可以做到这一点。大多数情况下,您希望一次处理一行,例如,您可以使用whileline=getsend或STDIN.each_linedo|line|end或者通过使用-n开关运行ruby,例如,这意味着上述循环之一(在每次迭代中将
如何扫描上传文件中的病毒、木马等?只是想阻止一些用户上传一些讨厌的东西。我正在使用Heroku和AmazonS3。 最佳答案 Checkoutthis它支持REST/JSON防病毒网络服务。 关于ruby-on-rails-Rails/Heroku-如何对上传的文件进行反病毒扫描?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/9640516/
Ruby(1.9.3)文档似乎暗示scan等同于=~除了scan返回多个匹配项,而=~仅返回第一个匹配项,并且scan返回匹配数据,而=~返回索引。但是,在下面的示例中,这两种方法似乎对相同的字符串和表达式返回不同的结果。这是为什么?1.9.3p0:002>str="PerlandPython-thetwolanguages"=>"PerlandPython-thetwolanguages"1.9.3p0:008>exp=/P(erl|ython)/=>/P(erl|ython)/1.9.3p0:009>str=~exp=>01.9.3p0:010>str.scanexp=>[["er
一、扫描原因 (1)寻找到网站后台管理 (2)寻找未授权界面 (3)寻找网站更多隐藏信息 (4)通过使用目录扫描可以让我们发现这个网站存在多少个目录,多少个页面,探索出网站的整体结构。通过目录扫描我们还能扫描敏感文件,后台文件,数据库文件,和信息泄漏文件等等。二、方法1、robots.txt (1)Robots协议(RobotsExclusionProtocol)“网络爬虫排除标准”,网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。 (2)同时也记录网站所具有基本的目录。
自97年以来我一直在使用vi/vim进行各种快速编辑和管理任务,但最近才考虑使用它来替换Netbeans作为我选择的ruby编辑器。我发现一件事在Netbeans和Eclipse中非常有用的是Ctrl+Click“转到定义”功能,您可以在其中按住Ctrl键并单击一个类或方法,然后它将带您了解定义。现在,我玩过丰富的ctags和rails.vim,而且很接近,但没有雪茄。这就是我想要的:默认情况下在Netbeans和Eclipse中,您可以在本地rails中按住ctrl并单击本地方法或类项目,但你也可以ctrl+click定义在gems或用Ruby编写的系统库。以Netbeans为例
根据theOnigurumadocumentation,\d字符类型匹配:decimaldigitcharUnicode:General_Category--Decimal_Number但是,在包含所有Decimal_Number字符的字符串中扫描\d会导致仅匹配拉丁文0-9数字:#encoding:utf-8require'open-uri'html=open("http://www.fileformat.info/info/unicode/category/Nd/list.htm").readdigits=html.scan(/U\+([\da-f]{4})/i).flatten.
这个问题在这里已经有了答案:HowdoIcreatemultiplesubmitbuttonsforthesameforminRails?(7个答案)关闭9年前。所以..'save'%>'library'%>然后在我的Controller中:with_actiondo|a|a.savedoenda.librarydoendend问题是只有一个操作被调用...两个submit_tags调用相同的操作...知道为什么吗?或者我如何获得两个按钮以将表单提交给两种不同的方法?
我想获取索引以及扫描结果"abab".scan(/a/)我不仅想拥有=>["a","a"]还有那些比赛的索引[1,3]有什么建议吗? 最佳答案 试试这个:res=[]"abab".scan(/a/)do|c|res[["a",0],["a",2]] 关于ruby-在ruby中获取字符串扫描结果的索引,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/3520208/
IV.SYSTEMIMPLEMENTATIONWeadoptmodulardesignfollowingtheintegrationofblockchain.Itbringsmoreflexibilitybyseparatingtheimplementationofdifferentfunctionalities,sowecouldleveragetheadvantagesoftheblockchain-basedsmartcontractwhilereducingoverhead.Figure3illustrateshowdifferentmodulesareinvolvedintheint