Golang动态处理多个文件的实现方法

Golang动态处理多个文件的实现方法 你好,

我的程序开始变得有点庞大(目前大约300行)。其中让我觉得有点碍眼的一点是,我的程序需要为三个不同的文件分别执行打开、延迟关闭以及创建 buffio.NewScanner 的操作。然后,它还需要为每组数据创建不同的数组。我估计所有这些重复的代码总共占了大约30-40行。有没有办法可以在一个循环中完成这些工作?或者从编程的角度来看,处理这类数据的首选方法是什么?

我曾尝试创建一个文件名数组并进行循环处理,但看起来不太对劲。我也注意到其他帖子提到 Go 不支持动态变量,所以任何帮助、想法或评论对我来说都很有用。

谢谢, Joe

8 回复

完美,

我有点懊恼自己没想到这一点……但非常感谢您的反馈。

更多关于Golang动态处理多个文件的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


振作起来!传统的思路是将公共逻辑分离,这将提高代码的可复用性和可维护性。

bufio.Scanner 返回的行不包含行结束符。因此没有行结束符需要移除或用于分割。

请发布一些您正在使用的代码,以便更好地了解您想要实现的目标。

祝好。

三次文件读取操作并不完全相同。最后一次读取没有移除行尾的换行符。不确定这是有意为之还是疏忽。

除此之外,您提出的解决方案当然是完美的。使用 TrimRight 确实更可取,或者我认为以下方法可能效率更高:

txt := s.Text()
res = append(res, txt[:len(txt)-1])
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	iplist, err := read("file.txt")
	if err != nil {
		panic(err)
	}
	subnet, err := read("file2.txt")
	if err != nil {
		panic(err)
	}
	ngdomain, err := read("file3.txt")
	if err != nil {
		panic(err)
	}

	fmt.Println(iplist, subnet, ngdomain)
}

func read(file string) ([]string, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}

	defer f.Close()

	var res []string
	s := bufio.NewScanner(f)
	for s.Scan() {
		res = append(res, strings.Split(s.Text(), "\n")[0])
		// 如果你只想移除文本末尾的换行符,你应该使用以下代码
		// res = append(res, strings.TrimRight(s.Text(), "\n"))
	}

	return res, nil
}

基本上,我有一段代码看起来像下面这样: 目前,我一直在尝试思考如何清理它,或者如何重用代码。我没有编程背景,但我觉得应该有更好的方法。

hostlist, _ := os.Open("file.txt")
//hostlist, _ := os.Open("temp")
filesubnetblacklist, _ := os.Open("file2.txt")
gooddomainlist, _ := os.Open("file3.txt")
defer hostlist.Close()
defer filesubnetblacklist.Close()
defer gooddomainlist.Close()
hostbuff := bufio.NewScanner(hostlist)
fileScanner := bufio.NewScanner(filesubnetblacklist)

domainbuff := bufio.NewScanner(gooddomainlist)

for domainbuff.Scan() {
    s := strings.Split(domainbuff.Text(), "\n")
    ngdomain = append(ngdomain, s[0])
}
for fileScanner.Scan() {
    s := strings.Split(fileScanner.Text(), "\n")
    subnet = append(subnet, s[0])
}
for hostbuff.Scan() {
    iplist = append(iplist, hostbuff.Text())
}

在Go中处理多个文件时,可以通过切片和结构体来消除重复代码。以下是一个示例实现:

package main

import (
    "bufio"
    "fmt"
    "os"
)

type FileProcessor struct {
    Filename string
    Lines    []string
    Scanner  *bufio.Scanner
    File     *os.File
}

func main() {
    // 定义要处理的文件列表
    files := []string{"file1.txt", "file2.txt", "file3.txt"}
    
    // 创建处理器切片
    processors := make([]*FileProcessor, len(files))
    
    // 循环处理每个文件
    for i, filename := range files {
        processor, err := processFile(filename)
        if err != nil {
            fmt.Printf("处理文件 %s 时出错: %v\n", filename, err)
            continue
        }
        processors[i] = processor
    }
    
    // 使用处理后的数据
    for _, p := range processors {
        if p != nil {
            fmt.Printf("文件 %s 有 %d 行数据\n", p.Filename, len(p.Lines))
            // 处理p.Lines中的数据
        }
    }
    
    // 清理资源
    for _, p := range processors {
        if p != nil && p.File != nil {
            p.File.Close()
        }
    }
}

func processFile(filename string) (*FileProcessor, error) {
    // 打开文件
    file, err := os.Open(filename)
    if err != nil {
        return nil, err
    }
    
    processor := &FileProcessor{
        Filename: filename,
        File:     file,
        Scanner:  bufio.NewScanner(file),
    }
    
    // 读取所有行
    for processor.Scanner.Scan() {
        processor.Lines = append(processor.Lines, processor.Scanner.Text())
    }
    
    // 检查扫描错误
    if err := processor.Scanner.Err(); err != nil {
        file.Close()
        return nil, err
    }
    
    return processor, nil
}

如果需要更通用的解决方案,可以使用接口:

package main

import (
    "bufio"
    "fmt"
    "os"
)

type FileHandler interface {
    Process() error
    GetData() []string
    Close()
}

type TextFileHandler struct {
    filename string
    file     *os.File
    scanner  *bufio.Scanner
    lines    []string
}

func NewTextFileHandler(filename string) *TextFileHandler {
    return &TextFileHandler{
        filename: filename,
    }
}

func (h *TextFileHandler) Process() error {
    var err error
    h.file, err = os.Open(h.filename)
    if err != nil {
        return err
    }
    
    h.scanner = bufio.NewScanner(h.file)
    for h.scanner.Scan() {
        h.lines = append(h.lines, h.scanner.Text())
    }
    
    return h.scanner.Err()
}

func (h *TextFileHandler) GetData() []string {
    return h.lines
}

func (h *TextFileHandler) Close() {
    if h.file != nil {
        h.file.Close()
    }
}

func main() {
    handlers := []FileHandler{
        NewTextFileHandler("file1.txt"),
        NewTextFileHandler("file2.txt"),
        NewTextFileHandler("file3.txt"),
    }
    
    // 处理所有文件
    for _, handler := range handlers {
        if err := handler.Process(); err != nil {
            fmt.Printf("处理错误: %v\n", err)
            continue
        }
        
        data := handler.GetData()
        fmt.Printf("读取到 %d 行数据\n", len(data))
        // 处理数据
    }
    
    // 关闭所有文件
    for _, handler := range handlers {
        handler.Close()
    }
}

如果只需要简单的文件读取,可以使用更简洁的闭包方式:

package main

import (
    "bufio"
    "fmt"
    "os"
)

func processFiles(filenames []string, processor func(filename string, lines []string) error) error {
    for _, filename := range filenames {
        file, err := os.Open(filename)
        if err != nil {
            return err
        }
        
        scanner := bufio.NewScanner(file)
        var lines []string
        for scanner.Scan() {
            lines = append(lines, scanner.Text())
        }
        
        if err := scanner.Err(); err != nil {
            file.Close()
            return err
        }
        
        file.Close()
        
        if err := processor(filename, lines); err != nil {
            return err
        }
    }
    return nil
}

func main() {
    files := []string{"file1.txt", "file2.txt", "file3.txt"}
    
    err := processFiles(files, func(filename string, lines []string) error {
        fmt.Printf("文件 %s 包含 %d 行\n", filename, len(lines))
        // 处理lines数据
        return nil
    })
    
    if err != nil {
        fmt.Printf("处理文件时出错: %v\n", err)
    }
}

这些方法都能有效减少重复代码,第一种方法适合需要保留文件数据的场景,第二种方法提供了更好的扩展性,第三种方法最为简洁。

回到顶部