beancount-gs/script/file.go

377 lines
8.9 KiB
Go

package script
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
)
func FileIfExist(filePath string) bool {
_, err := os.Stat(filePath)
if nil != err {
return false
}
if os.IsNotExist(err) {
return false
}
return true
}
func ReadFile(filePath string) ([]byte, error) {
content, err := ioutil.ReadFile(filePath)
if nil != err {
LogSystemError("Failed to read file (" + filePath + ")")
return content, err
}
LogSystemInfo("Success read file (" + filePath + ")")
return content, nil
}
func WriteFile(filePath string, content string) error {
err := ioutil.WriteFile(filePath, []byte(content), 0777)
if err != nil {
LogSystemError("Failed to write file (" + filePath + ")")
return err
}
LogSystemInfo("Success write file (" + filePath + ")")
return nil
}
func AppendFileInNewLine(filePath string, content string) error {
err := CreateFileIfNotExist(filePath)
if err != nil {
return err
}
content = "\r\n" + content
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
if err != nil {
LogSystemError("Failed to open file (" + filePath + ")")
return err
} else {
_, err = file.WriteString(content)
if err != nil {
LogSystemError("Failed to append file (" + filePath + ")")
return err
}
}
defer file.Close()
LogSystemInfo("Success append file (" + filePath + ")")
return err
}
func DeleteLinesWithText(filePath string, textToDelete string) error {
// 打开文件以供读写
file, err := os.OpenFile(filePath, os.O_RDWR, 0644)
if err != nil {
return err
}
defer file.Close()
// 创建一个缓冲读取器
scanner := bufio.NewScanner(file)
// 创建一个字符串切片,用于保存文件的每一行
var lines []string
// 逐行读取文件内容
for scanner.Scan() {
line := scanner.Text()
// 检查行是否包含要删除的文本
if !strings.Contains(line, textToDelete) {
lines = append(lines, line)
}
}
// 关闭文件
file.Close()
// 重新打开文件以供写入
file, err = os.OpenFile(filePath, os.O_RDWR|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer file.Close()
// 创建一个写入器
writer := bufio.NewWriter(file)
// 将修改后的内容写回文件
for _, line := range lines {
_, err := writer.WriteString(line + "\n")
if err != nil {
return err
}
}
// 刷新缓冲区,确保所有数据被写入文件
err = writer.Flush()
if err != nil {
return err
}
return nil
}
func CreateFile(filePath string) error {
if _, e := os.Stat(filePath); os.IsNotExist(e) {
_ = os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
f, err := os.Create(filePath)
if nil != err {
LogSystemError(filePath + " create failed")
return err
}
defer f.Close()
LogSystemInfo("Success create file " + filePath)
} else {
LogSystemInfo("File is exist " + filePath)
}
return nil
}
func CreateFileIfNotExist(filePath string) error {
if _, e := os.Stat(filePath); os.IsNotExist(e) {
_ = os.MkdirAll(filepath.Dir(filePath), os.ModePerm)
f, err := os.Create(filePath)
if nil != err {
LogSystemError(filePath + " create failed")
return err
}
defer f.Close()
LogSystemInfo("Success create file " + filePath)
}
return nil
}
func CopyFile(sourceFilePath string, targetFilePath string) error {
if !FileIfExist(sourceFilePath) {
panic("File is not found, " + sourceFilePath)
}
if !FileIfExist(targetFilePath) {
err := CreateFile(targetFilePath)
if err != nil {
return err
}
}
bytes, err := ReadFile(sourceFilePath)
if err != nil {
return err
}
err = WriteFile(targetFilePath, string(bytes))
if err != nil {
return err
}
return nil
}
func CopyDir(sourceDir string, targetDir string) error {
dirs, err := os.ReadDir(sourceDir)
if err != nil {
return err
}
err = MkDir(targetDir)
if err != nil {
return err
}
for _, dir := range dirs {
newSourceDir := filepath.Join(sourceDir, dir.Name())
newTargetDir := filepath.Join(targetDir, dir.Name())
if dir.IsDir() {
err := CopyFile(newSourceDir, newTargetDir)
if err != nil {
LogSystemError("Failed to copy dir from [" + newSourceDir + "] to [" + newTargetDir + "]")
return err
}
} else {
err := CreateFileIfNotExist(newTargetDir)
if err != nil {
return err
}
err = CopyFile(newSourceDir, newTargetDir)
if err != nil {
return err
}
}
}
return nil
}
func MkDir(dirPath string) error {
err := os.MkdirAll(dirPath, os.ModePerm)
if nil != err {
LogSystemError("Failed mkdir " + dirPath)
return err
}
LogSystemInfo("Success mkdir " + dirPath)
return nil
}
// FindConsecutiveMultilineTextInFile 查找文件中连续多行文本片段的开始和结束行号
func FindConsecutiveMultilineTextInFile(filePath string, multilineLines []string) (startLine, endLine int, err error) {
for i := range multilineLines {
multilineLines[i] = CleanString(multilineLines[i])
}
file, err := os.Open(filePath)
if err != nil {
return -1, -1, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
startLine = -1
endLine = -1
lineNumber := 0
matchIndex := 0
for scanner.Scan() {
lineNumber++
// 清理文件中的当前行
lineText := CleanString(scanner.Text())
// 检查当前行是否匹配多行文本片段的当前行
if lineText == multilineLines[matchIndex] {
if startLine == -1 {
startLine = lineNumber // 记录起始行号
}
matchIndex++
// 如果所有行都匹配完成,记录结束行号并退出循环
if matchIndex == len(multilineLines) {
endLine = lineNumber
break
}
} else {
// 如果匹配失败,重置匹配索引和起始行号
matchIndex = 0
startLine = -1
}
}
if err := scanner.Err(); err != nil {
return -1, -1, err
}
// 如果未找到完整的多行文本片段,则返回 -1
if startLine == -1 || endLine == -1 {
return -1, -1, fmt.Errorf("未找到连续的多行文本片段")
}
LogSystemInfo("Success find content in file " + filePath + " line range: " + string(rune(startLine)) + "," + string(rune(endLine)))
return startLine, endLine, nil
}
// CleanString 去除字符串中的首尾空白和中间的所有空格字符
func CleanString(str string) string {
if IsComment(str) {
return ""
}
result := getAccountWithNumber(str)
// 去除 " ", ";", "\r"
result = strings.ReplaceAll(result, ",", "")
result = strings.ReplaceAll(result, " ", "")
// 过滤空白的商户信息 ““
result = strings.ReplaceAll(result, "\"\"", "")
result = strings.ReplaceAll(result, ";", "")
result = strings.ReplaceAll(result, "\r", "")
// 清楚汇率转换
return result
}
// 正则提取:
// Assets:Flow:Cash:现金 -20.00 USD {xxx CNY, 2025-01-01} -> Assets:Flow:Cash:现金 -20.00 USD
func getAccountWithNumber(str string) string {
// 定义正则表达式模式
pattern := `^[^\{]+`
// 编译正则表达式
re := regexp.MustCompile(pattern)
// 使用正则提取匹配的部分
return re.FindString(str)
}
func IsComment(line string) bool {
trimmed := strings.TrimLeft(line, " ")
return strings.HasPrefix(trimmed, ";")
}
// 删除指定行范围的内容
func RemoveLines(filePath string, startLineNo, endLineNo int) ([]string, error) {
file, err := os.Open(filePath)
if err != nil {
return nil, 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 nil, err
}
// 检查行号的有效性
if startLineNo < 1 || endLineNo > len(lines) || startLineNo > endLineNo {
return nil, fmt.Errorf("行号范围无效")
}
// 删除从 startLineNo 到 endLineNo 的行(下标从 0 开始)
modifiedLines := append(lines[:startLineNo-1], lines[endLineNo:]...)
return modifiedLines, nil
}
// 在指定行号插入多行文本
func InsertLines(lines []string, startLineNo int, newLines []string) ([]string, error) {
// 检查插入位置的有效性
if startLineNo < 1 || startLineNo > len(lines)+1 {
return nil, fmt.Errorf("插入行号无效")
}
// 在指定位置插入新的内容
modifiedLines := append(lines[:startLineNo-1], append(newLines, lines[startLineNo-1:]...)...)
return modifiedLines, nil
}
// 写回文件
func WriteToFile(filePath string, lines []string) error {
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
// 将修改后的内容写回文件
writer := bufio.NewWriter(file)
for _, line := range lines {
_, err := writer.WriteString(line + "\n")
if err != nil {
return err
}
}
LogSystemInfo("Success write content in file " + filePath)
return writer.Flush()
}
// EnsureDirExists 确保目录存在,如果不存在则创建
func EnsureDirExists(path string) error {
dir := filepath.Dir(path)
return os.MkdirAll(dir, 0755)
}
// WriteFileWithDir 写入文件,确保目录存在
func WriteFileWithDir(filename string, data string) error {
// 确保目录存在
if err := EnsureDirExists(filename); err != nil {
return err
}
// 写入文件
return WriteFile(filename, data)
}