在Go中向.go文件追加内容可以通过多种方式实现,以下是几种常见的方法:
方法1:使用io/ioutil或os包读取和写入文件
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。