当前位置: 首页 > news >正文

网站上传到虚拟服务器中小企业建站系统

网站上传到虚拟服务器,中小企业建站系统,阿里云wordpress外网访问,做品牌网站找谁嗨#xff0c;大家好#xff01;我是波罗学。本文是系列文章 Go 技巧第十七篇#xff0c;系列文章查看#xff1a;Go 语言技巧。 本文将介绍 Go 如何按行读取文件#xff0c;基于此会逐步延伸到如何按块读取文件。 引言 我们将要介绍的按行读取文件的方式其实是非常适合… 嗨大家好我是波罗学。本文是系列文章 Go 技巧第十七篇系列文章查看Go 语言技巧。 本文将介绍 Go 如何按行读取文件基于此会逐步延伸到如何按块读取文件。 引言 我们将要介绍的按行读取文件的方式其实是非常适合处理超大文件。 按行读取文件相较于一次性载入有着很多优势如内存效率高、处理速度快、实时性高、可扩展性强和灵活度高等特别是当遇到处理大文件时这些优势会更加明显。 稍微展开说下各个优势吧。 内存效率高因为是按行读取处理完一行就会丢弃内存占用将大大减少。 处理速度快主要体现在逐行处理时因为无需等待全量数据能更快开始而且如果无顺序要求还可并行计算以最大化利用计算资源进一步提升处理速度。 实时性高因为按行读取无需一次加载全量数据自然有 实时性高 的特点这对于处理实时流数据如日志数据非常有用。 可扩展性强按行读取这种方式不仅仅适用于小文件大文件同样使用有了统一的处理方式即使未来数据量膨胀也易于扩展。 灵活度高因为是一行行的处理如果想停止随时可以。如果继续之前的流程我们只要重新启动从之前的位置继续处理即可。 按行读取其实只是按块读取的一种特殊形式分隔符是 \n自然地上述的优势也同样适用于按块读取文件。 本文的重点在于如何使用 GO 实现按行读取基于的是标准库的 bufio.Reader 和 bufio.Scanner 。 正式进入主题吧。 准备一个文本文件 我们先准备一个文本文件 example.txt内容如下 This post covers the Golang Interface. Let’s dive into it.Duck TypingTo understand Go’s interfaces, it’s crucial to grasp the Duck Typing concept.So, what’s Duck Typing?基于 bufio.Reader Go 中的按行读取文件首先可通过 bufio 提供的 Reader 类型实现。 使用 Reader.ReadLine Reader 中有一个名为 ReadLine 的方法顾名思义它的作用就是按行读取文件的。 演示代码 file, err : os.Open(example.txt) if err ! nil {panic(err) } defer func() { _ file.Close() }()reader : bufio.NewReader(file) for {line, _, err : reader.ReadLine() // 按行读取文件if err io.EOF { // 用于判断文件是否读取到结尾break}if err ! nil {panic(err)}fmt.Printf(%s\n, line) }重点就是那句 line, _, err : reader.ReadLine()返回值的第一值是读取的内容第三个值是错误信息。 执行与输出 $ go run main.go This post covers the Golang Interface. Let’s dive into it.Duck TypingTo understand Go’s interfaces, it’s crucial to grasp the Duck Typing concept.So, what’s Duck Typing?和我们预期的一样输出了完整的文本信息。 要提醒的是ReadLine 读取的内容不包括行尾符如 “\r\n” 或 “\n”。也就是说当读取到一行数据时要自行处理可能的行尾符差异尤其是在处理来自不同操作系统的文本数据时。 还有ReadLine 省略的第二个参数名为 isPrefix它表示是否是前缀的意思如果 isPrefix 为 true 表示返回的 line 被截断了而截断原因很可能是行的内容大小大于缓冲区。我们可以在初始化时通过 bufio.NewReaderSize(rd io.Reader, size int) 调整默认缓冲区大小。 不过这并非最优的解法。 使用 Reader.ReadString 解决大行读取被截断的问题还可用 bufio.Reader 的另外一个方法 ReadString 解决。 它与 ReadLine 类似不过在单个 buffer 不足以容纳单行内容时它会多次读取直到找到目标分割符合并多次读取的内容。 示例代码 reader : bufio.NewReader(file) for {line, err : reader.ReadString(\n)if err io.EOF {break}if err ! nil {panic(err)}fmt.Printf(%s\n, line) }重点就是那句 reader.ReadString(\n)它的入参是分割符delim即 ‘\n’而返回值分别读取内容line和错误err)。 相较于 ReadLineReadString 显然是更加灵活无大行读取被截断的问题而且分割符也可自定义。但只支持单一字节的分割符自定义还不够完美如我们想按多个字符如 .|, 等等分割文本或者按照大小分块读取就没有那么方便了。 我们继续引入另一个 Go 标准提供的按行读取文件的方案即 bufio.Scanner。 使用 bufio.Scanner 为了由浅入深地介绍 bufio.Scanner 的使用我们还是先从 bufio.Scanner 实现按行读取讲起吧。 一个示例代码了解 bufio.Scanner 的基本使用。 // 创建文件的扫描器用于逐行读取文件 scanner : bufio.NewScanner(file) // 循环直到文件结束 for scanner.Scan() {// 处理每行的内容打印fmt.Println(scanner.Text()) }// 最后检查扫描过程中是否有错误发生 if err : scanner.Err(); err ! nil {panic(err) }这个例子中我们基于打开的文件描述符 file创建了一个 bufio.Scanner 变量 scanner它通过 scanner.Scan() 逐行扫描文件和 scanner.Text() 从 buffer 中获取扫描内容直到结束。 毫无疑问相对于 bufio.Reader以上通过 bufio.Scanner 实现的代码简洁很多而且错误处理也是集中在 for 循环完成后统一进行。 如何读取大行 bufio.Scanner 如何处理特别长的行呢 默认情况下bufio.Scanner 初始缓冲区是 4KB而最大 token 大小是 64KB即无法处理超过 64KB 的行。 来自源码中的定义如下所示 // MaxScanTokenSize 可定义 buffer 中 token 的最大 size // 除非用户通过 Scanner.Buffer 显式修改 // 缓冲区初始大小和 token 最大 size // 实际的最大标记大小可能会更小因为 // 缓冲区可能需要包含例如换行符之类的内容。 MaxScanTokenSize 64 * 1024 // 缓冲区的初始大小 startBufSize 4096 bufio.Scanner 中提供了 Scanner.Buffer() 方法可用于调整默认的缓冲区。 示例代码 const maxCapacity 1024 * 1024 // 例如1MB可读取任何 1MB 的行。 buf : make([]byte, maxCapacity) // 初始缓冲大小 1MB无需多次扩容 scanner.Buffer(buf, maxCapacity)在 scanner 扫描前加上这段代码会重新设置缓冲区将初始缓冲大小和最大容易都设置为 1MB这样就可以处理异常长的大行size 1MB了而且由于初始缓冲区大小就是最大容量也无需多次扩容缓冲。 缓冲区逻辑 为了更好理解上面的缓冲区配置我简单介绍下 bufio.Scanner 是的 Scan 文件读取逻辑以及缓冲区是如何用的。 bufio.Scanner 内部有一个 s.buf 缓冲区当我们调用 scannder.Scan 方法时它会尝试用 io.Reader即示例中的 file 文件描述符中读取一个缓存大小的内容。它的具体实现是在 bufio.Scanner 的 Scan 方法中。如果当缓冲区大小不足以容纳一个完整的 tokenScanner 会自动增加缓冲区的大小。 接下来让我们实现 bufio.Scanner 按单词读取。 扩展思路 如果每次都读取这么大块的一整行和一次载入没有什么区别这明显已经失去了开头介绍的一行行读取的优势了。 除了直接读取整行是否还有什么更好的方法处理大行呢 我们可以尝试解放一些思路是否还有其他方式定义一次读取内容呢我们只要保证读取的内容有实际含义即可如按一句话一个单词或者固定的块大小的切割而非是纠结于是不是一整行。 分割规则定义 在正式介绍切割规则前先说明下什么是完整 token。前面一直在说 token如 MaxScanTokenSize 定义的就是 token 最大 size。 token 定义其实就是对一次读取内容的定义如一行文本一个单词或者一个固定大小的块。相对于特定分隔符分割规则更加灵活可以定义任意的分割方式。 而 bufio.Scanner 是一个非常灵活的工具它提供了自定义切割文本规则的函数 - Scanner.Split。 // 参数 // data []byte: 未处理数据的初始子串当前需要处理的输入数据。 // atEOF bool: 一个标志如果为 true则表示没有更多数据可处理。 // 返回值 // advance int: 需要在输入中前进多少以到达下一个标记的起始位置。 // token []byte: 要返回给用户的内容如果有。 // err error: 扫描过程中遇到的错误。 type SplitFunc func(data []byte, atEOF bool) (advance int, token []byte, err error)它的返回是分别读取内容的长度、读取的内容和错误信息。 默认情况下Scanner 按行分割ScanLines。 scanner.Split(bufio.ScanLines) // 默认配置按行读取我们可以通过自定义的 Split 函数改变这个默认行为如按单词分割。 示例代码 const input This is a test. This is only a test. scanner : bufio.NewScanner(strings.NewReader(input))// 设置分割函数为按单词分割 scanner.Split(bufio.ScanWords)// 逐个读取单词 for scanner.Scan() {fmt.Println(scanner.Text()) }if err : scanner.Err(); err ! nil {fmt.Fprintln(os.Stderr, reading input:, err) }输出 This is a test. This is only a test.现在无论多大的文件我们都可以通过巧妙定义切割方式来避免一次性读取的缺点了。 我之前利用 whispwer 识别油管视频的字幕有些视频的内容非常长超长字幕都在一行。现在我就可以通过如句号、问号、感叹号分割即可。现在我要做的定义这样一个 ScanSentences 函数。 示例代码 func ScanSentences(data []byte, atEOF bool) (advance int, token []byte, err error) {// 如果我们处于 EOF 并且有数据则返回剩余的数据if atEOF len(data) 0 {return len(data), data, nil}// 定义一个查找任意句子结束符的函数findSentenceEnd : func(data []byte) int {// 检查每个可能的句子结束符endIndex : -1for _, sep : range []byte{., ?, !} {if i : bytes.IndexByte(data, sep); i 0 {// 选择最小的 index 作为句子结尾if i endIndex || endIndex -1 {endIndex i}}}return endIndex}// 使用新的查找逻辑来查找句子结束位置if i : findSentenceEnd(data); i 0 {// 返回找到的句子包括句子结束符以及下一个 token 的起始位置return i 1, data[:i1], nil}return 0, nil, nil }我们写个 main 函数测试下 ScanSentences 的正确性吧。 示例代码 func main() {const input This is a test. This is only a test. Is this a test? \n Wow, what a brilliant test! Thanks for your help.scanner : bufio.NewScanner(strings.NewReader(input))scanner.Split(ScanSentences)for scanner.Scan() {text : scanner.Text()fmt.Printf(%s\n, strings.TrimSpace(text))}if err : scanner.Err(); err ! nil {panic(err)} }执行输出 $ go run main.go This is a test. This is only a test. Is this a test? Wow, what a brilliant test! Thanks for your help.或者按照固定大小分批读取文件SplitBatchSize 示例代码 // ScanBatchSize 返回一个 bufio.SplitFunc 函数该函数按照固定的大小分割数据。 // 如果数据大小不足一个完整的批次并且已经到达 EOF则返回剩余的数据。 func ScanBatchSize(batchSize int) bufio.SplitFunc {return func(data []byte, atEOF bool) (advance int, token []byte, err error) {// 如果数据大小达到或超过批次大小或者在 EOF 时有剩余数据if len(data) batchSize || (atEOF len(data) 0) {// 如果当前批次大小超过剩余数据大小则只返回剩余数据if len(data) batchSize {return len(data), data[:], nil}// 否则返回一个完整批次的大小和数据return batchSize, data[:batchSize], nil}// 如果没有足够的数据并且没有到达 EOF需要更多数据来形成一个完整的批次if !atEOF {return 0, nil, nil}// 处理到达 EOF 但没有剩余数据的情况return 0, nil, nil} }SplitBatchSize 是一个闭包它的返回值是我们期待的 SplitFunc。我们可传递参数配置每次读取内容的大小。具体可自行测试这里就演示了。 不得不说 到这里我还是想再提一点每次从文件中读取内容大小是由传入系统调用 read() 函数时传入参数 buf 大小决定的而不是由所谓按行还是按块确定的。按行按块是基于读取出来的二次处理的结果。 之所以要提这点因为我之前看到一些文章说按块相比按行读取减少了读取的次数。 结论 本文详细介绍了在 Go 中如何使用 bufio.Reader 和 bufio.Scanner 按行或按块读取文件通过利用 GO 的标准库能力我们有了更加灵活、高效处理大型文本文件的策略。 最后感谢阅读希望本文对你有所帮助。
http://www.pierceye.com/news/861492/

相关文章:

  • 如何用织梦程序制作多个页面网站免费域名解析网站建设
  • 安徽省建筑人员信息网广州百度seo优化排名
  • 北海网站建设培训机构专业
  • 江苏艺居建设有限公司网站企业营销网站开发建设专家
  • 莱芜网站优化排名西安工程建设工程信息网
  • 二手网站建设的策划php做网站都需要学什么软件
  • 作品集的个人网站怎么做抖音代运营怎么样呢
  • 电子商务网页设计与网站建设论文在线设计培训
  • 做旅游网站的项目背景软件开发手册
  • 宁波品牌网站设计app外包接活
  • 清远市住房和城乡建设局门户网站图片软件制作工具
  • 宝马itms做课网站网站开发群
  • 网站开发工作协议书范本谷歌优化软件
  • 什么网站都能进的浏览器企业融资方案
  • 网站建设公司领导致辞自己可以开发一个软件吗
  • 高端网站设计平台专门做二手书网站或app
  • 系网站建设工作总结大庆建设网站表格下载
  • 免费建站网站seo长春专业网站制作
  • 做网站公司哪家正规公司网站如何更改内容
  • 广州黄埔区建设局网站局wordpress怎么看访问量
  • 佛山找人做网站国家建设免费论文网站
  • 网站内容建设ppt网站建设header
  • 图书馆网站建设费用青海省住房建设厅网站
  • 重庆网站供奉战犯wordpress 关键字链接
  • 给个2021站你们懂得不花钱的深圳手机网站建设
  • 织梦图片自适应网站源码php企业网站源码推荐
  • 网站建网站建设网页微信头像logo在线制作
  • 微网站模板怎么做买了域名如何做网站
  • 新华美玉官方网站在线做维护一个网站要多少钱
  • 网站内容由什么组成部分网页网站设计价格