[{"data":1,"prerenderedAt":496},["ShallowReactive",2],{"post-\u002Fposts\u002Fgolang-linux-file":3,"surround-\u002Fposts\u002Fgolang-linux-file":487},{"id":4,"title":5,"body":6,"cover":472,"date":473,"description":474,"draft":475,"extension":476,"meta":477,"minutes":33,"navigation":317,"path":478,"seo":479,"stem":480,"tags":481,"updated":472,"__hash__":486},"posts\u002Fposts\u002Fgolang-linux-file.md","Golang在linux跨区移动文件失败",{"type":7,"value":8,"toc":470},"minimark",[9,13,73,76,466],[10,11,12],"p",{},"在项目涉及到了一个功能点，就是文件的移动，最开始是在windows下使用，然后发布到linux，业务第一阶段文件是一个分区下，代码还能正常运行，后期文件太多，一个分区装不下了，这时扩容了一个新的分区，然后就出现了*LinkError.错误，看到源码才知道，在非Unix系统下即使在同一个目录，Rename 不是原子操作。，源代码说明如下：",[14,15,20],"pre",{"className":16,"code":17,"language":18,"meta":19,"style":19},"language-go shiki shiki-themes tokyo-night github-light","\u002F\u002F Rename renames (moves) oldpath to newpath.\n\u002F\u002F If newpath already exists and is not a directory, Rename replaces it.\n\u002F\u002F OS-specific restrictions may apply when oldpath and newpath are in different directories.\n\u002F\u002F Even within the same directory, on non-Unix platforms Rename is not an atomic operation.\n\u002F\u002F If there is an error, it will be of type *LinkError.\nfunc Rename(oldpath, newpath string) error {\n    return rename(oldpath, newpath)\n}\n","go","",[21,22,23,31,37,43,49,55,61,67],"code",{"__ignoreMap":19},[24,25,28],"span",{"class":26,"line":27},"line",1,[24,29,30],{},"\u002F\u002F Rename renames (moves) oldpath to newpath.\n",[24,32,34],{"class":26,"line":33},2,[24,35,36],{},"\u002F\u002F If newpath already exists and is not a directory, Rename replaces it.\n",[24,38,40],{"class":26,"line":39},3,[24,41,42],{},"\u002F\u002F OS-specific restrictions may apply when oldpath and newpath are in different directories.\n",[24,44,46],{"class":26,"line":45},4,[24,47,48],{},"\u002F\u002F Even within the same directory, on non-Unix platforms Rename is not an atomic operation.\n",[24,50,52],{"class":26,"line":51},5,[24,53,54],{},"\u002F\u002F If there is an error, it will be of type *LinkError.\n",[24,56,58],{"class":26,"line":57},6,[24,59,60],{},"func Rename(oldpath, newpath string) error {\n",[24,62,64],{"class":26,"line":63},7,[24,65,66],{},"    return rename(oldpath, newpath)\n",[24,68,70],{"class":26,"line":69},8,[24,71,72],{},"}\n",[10,74,75],{},"不能使用这个方法来移动文件后，还有其他方式吗，目前处理的方案是先复制，然后再删除，实际使用下来的效率是低于最开始使用的Rename。 实例代码如下：",[14,77,79],{"className":16,"code":78,"language":18,"meta":19,"style":19},"func MoveFile(srcDir, destDir, move string) {\n    files, err := os.ReadDir(srcDir)\n    if err != nil {\n        return\n    }\n    for _, file := range files {\n        fileName := file.Name()\n        \u002F\u002F 判断文件是否存在，如果存在则删除，否则则移动对应的文件\n        toPath := filepath.Join(destDir, fileName)\n        srcPath := filepath.Join(srcDir, fileName)\n        if move == \"1\" {\n            log.Printf(\"Move file: %s\\n\", fileName)\n            err := os.Rename(srcPath, toPath)\n            if err != nil {\n                log.Printf(\"Failed to move the file: %s\\n\", err)\n            }\n        } else {\n            if _, err := os.Stat(toPath); err == nil {\n                \u002F\u002F 如果存在\n                err := os.Remove(srcPath)\n                if err != nil {\n                    return\n                }\n                fmt.Printf(\"Deleted: %s\\n\", file.Name())\n            } else {\n                \u002F\u002F 不存在\n                srcPath := filepath.Join(srcDir, fileName)\n                \u002F\u002F 复制文件\n                if err := copyFile(srcPath, toPath); err != nil {\n                    fmt.Println(\"Failed to copy:\", err)\n                    return\n                }\n                \u002F\u002F 删除源文件\n                if err := os.Remove(srcPath); err != nil {\n                    fmt.Println(\"Failed to delete the original file:\", err)\n                    return\n                }\n            }\n        }\n    }\n}\n\nfunc copyFile(src, dest string) error {\n    \u002F\u002F 打开源文件\n    srcFile, err := os.Open(src)\n    if err != nil {\n        log.Fatalf(\"Error opening source file: %v\", err)\n        return err\n    }\n    defer srcFile.Close()\n    \u002F\u002F 创建目标文件\n    dstFile, err := os.Create(dest)\n    if err != nil {\n        log.Fatalf(\"Error creating destination file: %v\", err)\n        return err\n    }\n    defer dstFile.Close()\n    \u002F\u002F 使用 bufio.NewReader 来提高读取性能\n    reader := bufio.NewReader(srcFile)\n    \u002F\u002F 复制文件内容\n    _, err = io.Copy(dstFile, reader)\n    if err != nil {\n        log.Fatalf(\"Error copying file: %v\", err)\n        return err\n    }\n    log.Println(\"File copied successfully\")\n    return nil\n}\n",[21,80,81,86,91,96,101,106,111,116,121,127,133,139,145,151,157,163,169,175,181,187,193,199,205,211,217,223,229,235,241,247,253,258,263,269,275,281,286,291,296,302,307,312,319,325,331,337,342,348,354,359,365,371,377,382,388,393,398,404,410,416,422,428,433,439,444,449,455,461],{"__ignoreMap":19},[24,82,83],{"class":26,"line":27},[24,84,85],{},"func MoveFile(srcDir, destDir, move string) {\n",[24,87,88],{"class":26,"line":33},[24,89,90],{},"    files, err := os.ReadDir(srcDir)\n",[24,92,93],{"class":26,"line":39},[24,94,95],{},"    if err != nil {\n",[24,97,98],{"class":26,"line":45},[24,99,100],{},"        return\n",[24,102,103],{"class":26,"line":51},[24,104,105],{},"    }\n",[24,107,108],{"class":26,"line":57},[24,109,110],{},"    for _, file := range files {\n",[24,112,113],{"class":26,"line":63},[24,114,115],{},"        fileName := file.Name()\n",[24,117,118],{"class":26,"line":69},[24,119,120],{},"        \u002F\u002F 判断文件是否存在，如果存在则删除，否则则移动对应的文件\n",[24,122,124],{"class":26,"line":123},9,[24,125,126],{},"        toPath := filepath.Join(destDir, fileName)\n",[24,128,130],{"class":26,"line":129},10,[24,131,132],{},"        srcPath := filepath.Join(srcDir, fileName)\n",[24,134,136],{"class":26,"line":135},11,[24,137,138],{},"        if move == \"1\" {\n",[24,140,142],{"class":26,"line":141},12,[24,143,144],{},"            log.Printf(\"Move file: %s\\n\", fileName)\n",[24,146,148],{"class":26,"line":147},13,[24,149,150],{},"            err := os.Rename(srcPath, toPath)\n",[24,152,154],{"class":26,"line":153},14,[24,155,156],{},"            if err != nil {\n",[24,158,160],{"class":26,"line":159},15,[24,161,162],{},"                log.Printf(\"Failed to move the file: %s\\n\", err)\n",[24,164,166],{"class":26,"line":165},16,[24,167,168],{},"            }\n",[24,170,172],{"class":26,"line":171},17,[24,173,174],{},"        } else {\n",[24,176,178],{"class":26,"line":177},18,[24,179,180],{},"            if _, err := os.Stat(toPath); err == nil {\n",[24,182,184],{"class":26,"line":183},19,[24,185,186],{},"                \u002F\u002F 如果存在\n",[24,188,190],{"class":26,"line":189},20,[24,191,192],{},"                err := os.Remove(srcPath)\n",[24,194,196],{"class":26,"line":195},21,[24,197,198],{},"                if err != nil {\n",[24,200,202],{"class":26,"line":201},22,[24,203,204],{},"                    return\n",[24,206,208],{"class":26,"line":207},23,[24,209,210],{},"                }\n",[24,212,214],{"class":26,"line":213},24,[24,215,216],{},"                fmt.Printf(\"Deleted: %s\\n\", file.Name())\n",[24,218,220],{"class":26,"line":219},25,[24,221,222],{},"            } else {\n",[24,224,226],{"class":26,"line":225},26,[24,227,228],{},"                \u002F\u002F 不存在\n",[24,230,232],{"class":26,"line":231},27,[24,233,234],{},"                srcPath := filepath.Join(srcDir, fileName)\n",[24,236,238],{"class":26,"line":237},28,[24,239,240],{},"                \u002F\u002F 复制文件\n",[24,242,244],{"class":26,"line":243},29,[24,245,246],{},"                if err := copyFile(srcPath, toPath); err != nil {\n",[24,248,250],{"class":26,"line":249},30,[24,251,252],{},"                    fmt.Println(\"Failed to copy:\", err)\n",[24,254,256],{"class":26,"line":255},31,[24,257,204],{},[24,259,261],{"class":26,"line":260},32,[24,262,210],{},[24,264,266],{"class":26,"line":265},33,[24,267,268],{},"                \u002F\u002F 删除源文件\n",[24,270,272],{"class":26,"line":271},34,[24,273,274],{},"                if err := os.Remove(srcPath); err != nil {\n",[24,276,278],{"class":26,"line":277},35,[24,279,280],{},"                    fmt.Println(\"Failed to delete the original file:\", err)\n",[24,282,284],{"class":26,"line":283},36,[24,285,204],{},[24,287,289],{"class":26,"line":288},37,[24,290,210],{},[24,292,294],{"class":26,"line":293},38,[24,295,168],{},[24,297,299],{"class":26,"line":298},39,[24,300,301],{},"        }\n",[24,303,305],{"class":26,"line":304},40,[24,306,105],{},[24,308,310],{"class":26,"line":309},41,[24,311,72],{},[24,313,315],{"class":26,"line":314},42,[24,316,318],{"emptyLinePlaceholder":317},true,"\n",[24,320,322],{"class":26,"line":321},43,[24,323,324],{},"func copyFile(src, dest string) error {\n",[24,326,328],{"class":26,"line":327},44,[24,329,330],{},"    \u002F\u002F 打开源文件\n",[24,332,334],{"class":26,"line":333},45,[24,335,336],{},"    srcFile, err := os.Open(src)\n",[24,338,340],{"class":26,"line":339},46,[24,341,95],{},[24,343,345],{"class":26,"line":344},47,[24,346,347],{},"        log.Fatalf(\"Error opening source file: %v\", err)\n",[24,349,351],{"class":26,"line":350},48,[24,352,353],{},"        return err\n",[24,355,357],{"class":26,"line":356},49,[24,358,105],{},[24,360,362],{"class":26,"line":361},50,[24,363,364],{},"    defer srcFile.Close()\n",[24,366,368],{"class":26,"line":367},51,[24,369,370],{},"    \u002F\u002F 创建目标文件\n",[24,372,374],{"class":26,"line":373},52,[24,375,376],{},"    dstFile, err := os.Create(dest)\n",[24,378,380],{"class":26,"line":379},53,[24,381,95],{},[24,383,385],{"class":26,"line":384},54,[24,386,387],{},"        log.Fatalf(\"Error creating destination file: %v\", err)\n",[24,389,391],{"class":26,"line":390},55,[24,392,353],{},[24,394,396],{"class":26,"line":395},56,[24,397,105],{},[24,399,401],{"class":26,"line":400},57,[24,402,403],{},"    defer dstFile.Close()\n",[24,405,407],{"class":26,"line":406},58,[24,408,409],{},"    \u002F\u002F 使用 bufio.NewReader 来提高读取性能\n",[24,411,413],{"class":26,"line":412},59,[24,414,415],{},"    reader := bufio.NewReader(srcFile)\n",[24,417,419],{"class":26,"line":418},60,[24,420,421],{},"    \u002F\u002F 复制文件内容\n",[24,423,425],{"class":26,"line":424},61,[24,426,427],{},"    _, err = io.Copy(dstFile, reader)\n",[24,429,431],{"class":26,"line":430},62,[24,432,95],{},[24,434,436],{"class":26,"line":435},63,[24,437,438],{},"        log.Fatalf(\"Error copying file: %v\", err)\n",[24,440,442],{"class":26,"line":441},64,[24,443,353],{},[24,445,447],{"class":26,"line":446},65,[24,448,105],{},[24,450,452],{"class":26,"line":451},66,[24,453,454],{},"    log.Println(\"File copied successfully\")\n",[24,456,458],{"class":26,"line":457},67,[24,459,460],{},"    return nil\n",[24,462,464],{"class":26,"line":463},68,[24,465,72],{},[467,468,469],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":19,"searchDepth":39,"depth":39,"links":471},[],null,"2024-03-19","当前基于Golang 1.22.2 版本实现",false,"md",{},"\u002Fposts\u002Fgolang-linux-file",{"title":5,"description":474},"posts\u002Fgolang-linux-file",[482,483,484,485],"golang","linux","LinkError","文件移动","NJw72w-e66RR4J9x3mGHbJz-yAK--RQdrF5nfzVQWkE",[488,492],{"title":489,"path":490,"stem":491,"children":-1},"如何自定义处理Golang Cmd的日志输出","\u002Fposts\u002Fgolang-logger-out","posts\u002Fgolang-logger-out",{"title":493,"path":494,"stem":495,"children":-1},"Golang exec.Cmd在Kill后不能关闭进程","\u002Fposts\u002Fgolang-exec-kill","posts\u002Fgolang-exec-kill",1786707084689]