You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang文件夹监控文件的高效安全原地修改实现问询

需求与问题

我编写了一个Go程序,用于监控指定文件夹并检测新文件,对符合条件的文件进行内容修改。当前实现存在两个核心问题:

  • 效率低下:需将整个文件内容读入内存后修改
  • 数据安全风险:删除原文件后再写入新文件,过程中若出错会导致数据丢失

我希望实现真正的原地直接修改(仅修改小部分内容),虽已参考资料改进代码,但未实现类似Seek的原生原地编辑逻辑,特寻求Go语言的正确实现方案。


正确的原地修改实现方案

要实现安全高效的原地文件编辑,核心是定位目标内容位置后直接修改原文件,无需删除重建。以下是针对你的需求的具体实现:

package main

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"strings"
	"time"
)

const dir = "dir00003"

func main() {
	fmt.Println("Running...")

	for {
		time.Sleep(60 * time.Second)
		files, err := os.ReadDir(dir)
		if err != nil {
			fmt.Println("Failed to read transfer folder. There must be a folder named `dir00003`!")
			continue
		}

		for _, v := range files {
			if strings.Contains(v.Name(), "pmi") {
				continue
			}
			if time.Now().Sub(v.ModTime()) < (time.Minute * 2) {
				modifyFileInPlace(fmt.Sprintf("%s/%s", dir, v.Name()))
			}
		}
		fmt.Printf("\nDone with round\n")
	}
}

func modifyFileInPlace(filePath string) {
	// 以读写模式打开文件
	f, err := os.OpenFile(filePath, os.O_RDWR, 0644)
	if err != nil {
		fmt.Printf("Couldn't open file: %s\n", filePath)
		return
	}
	defer f.Close()

	// 读取文件内容(大文件建议改用流式查找,避免内存占用过高)
	content, err := io.ReadAll(f)
	if err != nil {
		fmt.Printf("Couldn't read file: %s\n", filePath)
		return
	}

	target := []byte("<program_parameters/>")
	pos := bytes.Index(content, target)
	if pos == -1 {
		return // 未找到目标内容,直接跳过
	}

	// 构造修改后的内容:移除目标字符串
	newContent := append(content[:pos], content[pos+len(target):]...)

	// 定位到文件开头,写入新内容
	if _, err := f.Seek(0, io.SeekStart); err != nil {
		fmt.Printf("Seek failed: %s\n", filePath)
		return
	}
	if _, err := f.Write(newContent); err != nil {
		fmt.Printf("Write failed: %s\n", filePath)
		return
	}

	// 截断文件到新内容长度,清除原文件末尾的残留数据
	if err := f.Truncate(int64(len(newContent))); err != nil {
		fmt.Printf("Truncate failed: %s\n", filePath)
		return
	}

	fmt.Printf("Successfully modified file in-place: %s\n", filePath)
}

方案优势

  • 数据安全:直接在原文件上修改,无需删除重建,即使中途出错,原文件仅会出现部分修改,不会完全丢失
  • 效率提升:对于大文件可优化为流式查找目标位置,无需将整个文件加载到内存
  • 原生原地编辑:利用Seek定位、Write覆盖、Truncate截断的组合,实现真正的原地修改逻辑

原实现代码
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"time"
)

const dir = "dir00003"

func main() {

	fmt.Println("Running...")

	//Go into a loop forever
	for {

		//Wait 60 seconds before taking any action.
		time.Sleep(60 * time.Second)
		//Read all of the file data for all files in the directory:
		files, err := ioutil.ReadDir(dir)
		if err != nil {
			fmt.Println("Failed to read transfer folder. There must be a folder named `dir00003`!")
			continue
		}

		for _, v := range files {

			//if this is an index file, skip over it as we don't care:
			if strings.Contains(v.Name(), "pmi") {
				continue
			}

			//if the file was created within the last 2 minutes, we should check if we need to modify it
			if time.Now().Sub(v.ModTime()) < (time.Minute * 2) {

				//open the file
				f, err := os.Open(fmt.Sprintf("%s/%s", dir, v.Name()))
				if err != nil {
					fmt.Printf("\tCouldn't open file: %s\n", v.Name())
					continue
				}

				defer f.Close()
				//read all of the bytes of the file
				bs, err := ioutil.ReadAll(f)
				if err != nil {
					fmt.Printf("\tCouldn't read bytes from %s\n", v.Name())
					continue
				}

				//see if the <program_parameters/> tag is in the file
				b := bytes.Contains(bs, []byte("<program_parameters/>"))

				//if the tag is in the file, we should replace it, otherwise we move on to the next file
				if b {
					//replace the tag with nothing. Only look for the first instance and then abort the process of replacing.
					rbs := bytes.Replace(bs, []byte("<program_parameters/>"), []byte(""), 1)
					//close the file so we can delete it.
					f.Close()
					//delete the exisint file.
					os.Remove(fmt.Sprintf("%s/%s", dir, v.Name()))

					//create a new file with the same original name:
					nf, err := os.Create(fmt.Sprintf("%s/%s", dir, v.Name()))
					if err != nil {
						fmt.Printf("\tFailed to create new file for %s\n", v.Name())
						continue
					}

					//write all of the bytes that we have in memory to our new file.
					_, err = nf.Write(rbs)
					if err != nil {
						fmt.Println("Failed to write to new file %s\n", v.Name())
						continue
					}
					//close our new file
					nf.Close()

					fmt.Printf("Modified new file: %s", v.Name())

				} else {
					continue
				}

			}

		}

		fmt.Printf("\nDone with round\n")

	}

	fmt.Println("PROGRAM STOPPED RUNNING!!")

	return
}

改进后的代码片段
// Open the file
f, err := os.OpenFile(fmt.Sprintf("%s/%s", dir, v.Name()), os.O_RDWR, 0644)
if err != nil {
    fmt.Printf("Couldn't open file: %s\n", v.Name())
    continue
}

defer f.Close()

// Create a buffer to read the contents of the file
var buffer bytes.Buffer
_, err = buffer.ReadFrom(f)
if err != nil {
    fmt.Printf("Couldn't read bytes from %s\n", v.Name())
    continue
}

if strings.Contains(buffer.String(), "<program_parameters/>") {
    
    rbs := bytes.Replace(buffer.Bytes(), []byte("<program_parameters/>"), []byte(""), 1)

    err = ioutil.WriteFile(fmt.Sprintf("%s/%s",dir, v.Name()), rbs, 0660)
    if err != nil {fmt.Printf("Failed to WriteFile: %v", err.Error()); continue}                    

    fmt.Printf("Modified file in place: %s\n", v.Name())
}

内容的提问来源于stack exchange,提问作者Jadefox10200

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 12:23:11