Go语言中如何复制文件且不覆盖已存在的同名文件
Go语言实现文件复制不覆盖、自动生成序号后缀文件名的方案
修正后完整可运行代码
package main import ( "fmt" "io" "log" "os" "path/filepath" "strings" ) // generateAvailableDest 生成不冲突的目标文件路径,冲突时自动加(n)后缀 func generateAvailableDest(originalDest string) string { // 如果原始路径不存在直接返回 if _, err := os.Stat(originalDest); os.IsNotExist(err) { return originalDest } // 拆分目录、基础文件名、扩展名 dir := filepath.Dir(originalDest) ext := filepath.Ext(originalDest) baseName := strings.TrimSuffix(filepath.Base(originalDest), ext) // 从1开始尝试序号后缀 counter := 1 for { newName := fmt.Sprintf("%s(%d)%s", baseName, counter, ext) newPath := filepath.Join(dir, newName) if _, err := os.Stat(newPath); os.IsNotExist(err) { return newPath } counter++ } } func main() { src := "./word_source.txt" originalDest := "./folder/word_destination.txt" // 先保证目标目录存在 destDir := filepath.Dir(originalDest) if err := os.MkdirAll(destDir, 0755); err != nil { log.Fatalf("创建目标目录失败: %v", err) } // 获取不冲突的目标路径 finalDest := generateAvailableDest(originalDest) fmt.Printf("最终写入路径:%s\n", finalDest) // 小文件可直接读写,大文件见下方优化方案 content, err := os.ReadFile(src) if err != nil { log.Fatalf("读取源文件失败: %v", err) } if err := os.WriteFile(finalDest, content, 0644); err != nil { log.Fatalf("写入目标文件失败: %v", err) } fmt.Println("文件复制完成") }
核心逻辑说明
- 文件名处理使用
path/filepath标准库函数,兼容Windows、Linux等不同系统的路径分隔符 - 自动判断原始目标文件是否存在,存在时从1开始递增拼接后缀,直到找到未被占用的文件名
- 新增了目标目录自动创建逻辑,避免目标文件夹不存在时报错
- 替换了已废弃的
ioutil相关接口,使用Go 1.16+推荐的os.ReadFile/os.WriteFile
大文件优化方案
如果需要复制GB级别的大文件,不建议直接将整个文件读入内存,可以改用流式复制逻辑降低内存占用:
// 流式复制大文件替换原有读写逻辑即可 srcFile, err := os.Open(src) if err != nil { log.Fatal(err) } defer srcFile.Close() destFile, err := os.Create(finalDest) if err != nil { log.Fatal(err) } defer destFile.Close() _, err = io.Copy(destFile, srcFile) if err != nil { log.Fatal(err) }
原有代码问题修正点
- 字符串字面量未加双引号,属于基础语法错误
- 缺少
log包的导入声明,调用log.Fatal会报错 - 只有文件不存在时的读取逻辑,缺少文件存在时的分支处理和最终写入逻辑
- 使用了已废弃的
ioutil.ReadFile接口,替换为更稳定的os.ReadFile
内容的提问来源于stack exchange,提问作者meena sushanth
相关产品推荐
相关产品推荐

