Golang如何向.go文件追加内容

Golang如何向.go文件追加内容 我想在 .go 文件的指定位置添加新行,例如: 我想在 fmt.Println("Hello, world) 之前添加 fmt.Println("new line")。 同时,我还想在 “fmt” 之后添加新行,例如 “myPackage”。

有人有示例吗?

package main

import (
  "fmt"
 //"myPackage"
)

func main() {
    //fmt.Println("new line")
    fmt.Println("Hello, world)
}
5 回复

将整个文件读取为 []string,向切片本身追加内容,然后用新的字符串切片覆盖文件。

func main() {
    fmt.Println("hello world")
}

更多关于Golang如何向.go文件追加内容的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好,你说得对,抱歉,我当时太累了,所以没有详细说明我做了什么。我已经解决了我的问题,下面是我的解决方案。

func main() {
    fmt.Println("hello world")
}

你能提供更多关于你试图做什么以及为什么这样做的背景信息吗?如果你有文件修改前后的样子,使用diff创建补丁然后应用它可能是最简单的方法。

否则,你被允许修改原始文件吗?如果是的话,你可以使用模板来实现:Go Playground - go.dev

如果不允许,你就必须将原始源代码解析成AST,然后使用像Fatih Arslan的astrewrite包这样的工具,以编程方式重写AST。

我通过以下代码解决了我的问题

package main

import (
  "log"
  "strings"
  "io/ioutil"
)

func main() {
	input, err := ioutil.ReadFile("file.go")// 这里我打开要修改的文件
	if err != nil {
		log.Fatalln(err)
	}

	lines := strings.Split(string(input), "\n")// 这里我存储文件中的所有行

	for i, line := range lines { // 这里我遍历所有文件行
		if strings.Contains(line, "import (") || strings.Contains(line, "import(") {//这里我搜索要替换和添加的行
			lines[i] = `import (
  "myPackage"`//这里我用新数据替换该行
		}

		if strings.Contains(line, "func main() {") || strings.Contains(line, "func main(){") {// 这里我遍历所有文件行
			lines[i] = `func main() {
  fmt.Println("new line")`//这里我用新数据替换该行
		}
    }

  output := strings.Join(lines, "\n")// 这里我连接并添加新行
	err = ioutil.WriteFile("file.go", []byte(output), 0644) // 这里我将新数据写入文件
	if err != nil {
		log.Fatalln(err)
	}
}

在Go中向.go文件追加内容可以通过多种方式实现,以下是几种常见的方法:

方法1:使用io/ioutilos包读取和写入文件

package main

import (
    "fmt"
    "io/ioutil"
    "strings"
)

func main() {
    // 读取文件内容
    content, err := ioutil.ReadFile("main.go")
    if err != nil {
        panic(err)
    }
    
    fileContent := string(content)
    
    // 在指定位置插入新行
    // 在 fmt.Println("Hello, world") 之前添加新行
    targetLine := `fmt.Println("Hello, world")`
    newLine := `    fmt.Println("new line")`
    
    if strings.Contains(fileContent, targetLine) {
        fileContent = strings.Replace(fileContent, targetLine, 
            newLine + "\n    " + targetLine, 1)
    }
    
    // 在 import 块中添加新包
    importStart := `import (`
    if strings.Contains(fileContent, importStart) {
        // 找到 import 块的结束位置
        importEnd := `)`
        importIndex := strings.Index(fileContent, importStart)
        importEndIndex := strings.Index(fileContent[importIndex:], importEnd)
        
        // 在 import 块中添加新包
        importBlock := fileContent[importIndex:importIndex+importEndIndex+1]
        newImportBlock := strings.Replace(importBlock, `"fmt"`, 
            `"fmt"` + "\n    \"myPackage\"", 1)
        
        fileContent = fileContent[:importIndex] + newImportBlock + 
            fileContent[importIndex+importEndIndex+1:]
    }
    
    // 写回文件
    err = ioutil.WriteFile("main.go", []byte(fileContent), 0644)
    if err != nil {
        panic(err)
    }
}

方法2:使用bufio逐行处理

package main

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

func insertLineInFile(filename string) error {
    // 打开文件
    file, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer file.Close()
    
    var lines []string
    scanner := bufio.NewScanner(file)
    
    // 读取所有行
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    
    if err := scanner.Err(); err != nil {
        return err
    }
    
    // 在指定位置插入新行
    for i, line := range lines {
        if strings.Contains(line, `fmt.Println("Hello, world")`) {
            // 在当前位置插入新行
            newLines := make([]string, 0, len(lines)+1)
            newLines = append(newLines, lines[:i]...)
            newLines = append(newLines, `    fmt.Println("new line")`)
            newLines = append(newLines, lines[i:]...)
            lines = newLines
            break
        }
    }
    
    // 处理 import 块
    inImportBlock := false
    for i, line := range lines {
        trimmed := strings.TrimSpace(line)
        
        if trimmed == "import (" {
            inImportBlock = true
            continue
        }
        
        if inImportBlock && trimmed == ")" {
            inImportBlock = false
            continue
        }
        
        if inImportBlock && strings.Contains(line, `"fmt"`) {
            // 在 fmt 之后添加新行
            lines[i] = line + "\n    \"myPackage\""
        }
    }
    
    // 写回文件
    output, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer output.Close()
    
    writer := bufio.NewWriter(output)
    for _, line := range lines {
        fmt.Fprintln(writer, line)
    }
    
    return writer.Flush()
}

func main() {
    err := insertLineInFile("main.go")
    if err != nil {
        panic(err)
    }
}

方法3:使用正则表达式进行精确匹配

package main

import (
    "fmt"
    "io/ioutil"
    "regexp"
)

func main() {
    content, err := ioutil.ReadFile("main.go")
    if err != nil {
        panic(err)
    }
    
    fileContent := string(content)
    
    // 在 fmt.Println("Hello, world") 之前添加新行
    pattern1 := regexp.MustCompile(`(\s+)fmt\.Println\("Hello, world"\)`)
    replacement1 := `${1}fmt.Println("new line")${0}`
    fileContent = pattern1.ReplaceAllString(fileContent, replacement1)
    
    // 在 import 块中添加新包
    pattern2 := regexp.MustCompile(`import\s*\(\s*([^)]+)"fmt"([^)]*)\)`)
    replacement2 := `import (
    "fmt"
    "myPackage"
)`
    fileContent = pattern2.ReplaceAllString(fileContent, replacement2)
    
    // 写回文件
    err = ioutil.WriteFile("main.go", []byte(fileContent), 0644)
    if err != nil {
        panic(err)
    }
}

方法4:使用AST(抽象语法树)进行精确操作

package main

import (
    "fmt"
    "go/ast"
    "go/parser"
    "go/printer"
    "go/token"
    "os"
    "strings"
)

func main() {
    fset := token.NewFileSet()
    
    // 解析文件
    node, err := parser.ParseFile(fset, "main.go", nil, parser.ParseComments)
    if err != nil {
        panic(err)
    }
    
    // 修改 import 声明
    for _, decl := range node.Decls {
        if genDecl, ok := decl.(*ast.GenDecl); ok && genDecl.Tok == token.IMPORT {
            // 添加新的 import
            newImport := &ast.ImportSpec{
                Path: &ast.BasicLit{
                    Kind:  token.STRING,
                    Value: `"myPackage"`,
                },
            }
            genDecl.Specs = append(genDecl.Specs, newImport)
        }
    }
    
    // 修改函数体
    ast.Inspect(node, func(n ast.Node) bool {
        if funcDecl, ok := n.(*ast.FuncDecl); ok && funcDecl.Name.Name == "main" {
            // 创建新的 Println 语句
            newStmt := &ast.ExprStmt{
                X: &ast.CallExpr{
                    Fun: &ast.SelectorExpr{
                        X:   ast.NewIdent("fmt"),
                        Sel: ast.NewIdent("Println"),
                    },
                    Args: []ast.Expr{
                        &ast.BasicLit{
                            Kind:  token.STRING,
                            Value: `"new line"`,
                        },
                    },
                },
            }
            
            // 在原有语句之前插入新语句
            funcDecl.Body.List = append([]ast.Stmt{newStmt}, funcDecl.Body.List...)
            return false
        }
        return true
    })
    
    // 写回文件
    output, err := os.Create("main.go")
    if err != nil {
        panic(err)
    }
    defer output.Close()
    
    err = printer.Fprint(output, fset, node)
    if err != nil {
        panic(err)
    }
}

这些方法各有优缺点:

  • 方法1和2适合简单的文本操作
  • 方法3适合复杂的模式匹配
  • 方法4使用AST可以确保语法正确性,但实现较为复杂

根据你的具体需求选择合适的方法。对于简单的追加操作,方法1或2通常足够;如果需要确保语法正确性,建议使用方法4。

回到顶部