• 一个简单的目录复制程序


    创建一个独立的 goroutine 遍历文件,主进程负责写入数据。程序会复制空目录,也可以设置只复制以 ".xx" 结尾的文件。
    严格来说这不是复制文件,而是写入新文件。因为这个程序是创建新文件,然后写入复制数据的。我们一般的 copy 命令是不会修改文件的 ctime(change time) 状态的。

    代码:

    // 一个简单的目录复制程序:一个独立的 goroutine 遍历目录,主进程负责将数据写入新目录。
    // 2014-11-02 Bing.L
    package main
    
    import (
    	"io"
    	"log"
    	"os"
    	"path/filepath"
    	"strings"
    )
    
    type FileInfo struct {
    	RelPath string
    	Size    int64
    	IsDir   bool
    	Handle  *os.File
    }
    
    //复制文件数据
    func ioCopy(srcHandle *os.File, dstPth string) (err error) {
    	dstHandle, err := os.OpenFile(dstPth, os.O_CREATE|os.O_WRONLY, os.ModePerm)
    	if err != nil {
    		return err
    	}
    
    	defer srcHandle.Close()
    	defer dstHandle.Close()
    
    	_, err = io.Copy(dstHandle, srcHandle)
    	return err
    }
    
    //遍历目录,将文件信息传入通道
    func WalkFiles(srcDir, suffix string, c chan<- *FileInfo) {
    	suffix = strings.ToUpper(suffix)
    
    	filepath.Walk(srcDir, func(f string, fi os.FileInfo, err error) error { //遍历目录
    		if err != nil {
    			log.Println("[E]", err)
    		}
    
    		fileInfo := &FileInfo{}
    		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) { //匹配文件
    			if fh, err := os.OpenFile(f, os.O_RDONLY, os.ModePerm); err != nil {
    				log.Println("[E]", err)
    			} else {
    				fileInfo.Handle = fh
    				fileInfo.RelPath, _ = filepath.Rel(srcDir, f) //相对路径
    				fileInfo.Size = fi.Size()
    				fileInfo.IsDir = fi.IsDir()
    			}
    
    			c <- fileInfo
    		}
    	})
    	close(c) //遍历完成,关闭通道
    }
    
    //写目标文件
    func WriteFiles(dstDir string, c <-chan *FileInfo) {
    	if err := os.Chdir(dstDir); err != nil { //切换工作路径
    		log.Fatalln("[F]", err)
    	}
    
    	for f := range c {
    		if fi, err := os.Stat(f.RelPath); os.IsNotExist(err) { //目标不存在
    			if f.IsDir {
    				if err := os.MkdirAll(f.RelPath, os.ModeDir); err != nil {
    					log.Println("[E]", err)
    				}
    			} else {
    				if err := ioCopy(f.Handle, f.RelPath); err != nil {
    					log.Println("[E]", err)
    				} else {
    					log.Println("[I] CP:", f.RelPath)
    				}
    			}
    		} else if !f.IsDir { //目标存在,而且源不是一个目录
    
    			if fi.IsDir() != f.IsDir { //检查文件名被目录名占用冲突
    				log.Println("[E]", "filename conflict:", f.RelPath)
    
    			} else if fi.Size() != f.Size { //源和目标的大小不一致时才重写
    				if err := ioCopy(f.Handle, f.RelPath); err != nil {
    					log.Println("[E]", err)
    				} else {
    					log.Println("[I] CP:", f.RelPath)
    				}
    			}
    		}
    	}
    }
    
    func main() {
    	files_ch := make(chan *FileInfo, 100)
    
    	go WalkFiles("E:\study", ".doc", files_ch) //在一个独立的 goroutine 中遍历文件
    	WriteFiles("E:\study.bak", files_ch)
    }
    
  • 相关阅读:
    Python环境搭建
    接口测试工具Jmeter
    接口测试工具postman
    fiddler -- 一个强大的抓包工具
    Pychram中使用reduce()函数报错:Unresolved reference 'reduce'
    Mac下用命令行获取苹果手机的UDID
    python 的 lambda使用笔记
    appium报错:An unknown server-side error occurred while processing the command. Original error: Could not proxy command to remote server. Original error: Error: read ECONNRESET
    Pycharm中使用from appium import webdriver时报错:ModuleNotFoundError: No module named 'appium'
    如何升级pip3
  • 原文地址:https://www.cnblogs.com/bing-l/p/4069413.html
Copyright © 2020-2023  润新知