1. 程式人生 > >在windows下用go語言寫跨卷批量移動小工具

在windows下用go語言寫跨卷批量移動小工具

時值我小病在家休養生息,喜歡跳廣場舞的外公來尋求我的幫助,他們跳廣場舞是將存有歌曲的U盤插到音響上面,而音響大部分都是隻能顯示歌曲的索引index,不能直接顯示歌曲名,所以為了方便他們會在U盤裡面對歌曲進行排序。由於音響是定址按順序播放,意思就是在U盤裡面的歌曲需要一首一首的按順序複製過去,而且當對U盤歌曲進行增添的時候又需要按照順序重新複製一遍,可以說相當麻煩。為了將我從這重複的勞動中解放出來,我用go語言寫了一個小工具,本來想著分分鐘寫完,卻沒想到踩到了坑。
os包中有一個Rename()函式具有重新命名和移動的功能,其函式如下:

func Rename(oldpath, newpath string) error

Rename修改一個檔案的名字,移動一個檔案。可能會有一些個作業系統特定的限制。

在windows系統下面使用該函式,oldpathnewpath在同一個磁碟/卷下面能正常使用,可我需要將音樂移動到U盤上,當使用這個函式的時候出現了:

The system cannot move the file to a different disk drive.

搜尋Githubissues,發現Rename在windows中不能進行跨磁碟/卷操作。
為了實現跨磁碟/卷操作,一種方法是直接呼叫windows API,於是在windows api docs中搜索到movefileex()函式能夠實現該功能,但是在go語言的syscall

包中只有movefile()函式,其函式如下:

func MoveFile(from *uint16, to *uint16) (err error)

實現檔案移動的函式可以寫成:

func movefile(oldpath, newpath string) error { //跨卷移動
    from, err := syscall.UTF16PtrFromString(oldpath)
    if err != nil {
        return err
    }
    to, err := syscall.UTF16PtrFromString(newpath)
    if err != nil {
        return err
    }
    return syscall.MoveFile(from, to)//windows API

}

當我們讀取oldpath目錄裡面的檔案時呼叫io/ioutil包的ReadDir()函式可按照資料夾內的排序方式批量讀入檔名,其函式實現如下:

func filenamelist(filepath string) []string {
    var list []string
    rd, err := ioutil.ReadDir(filepath) //遍歷目錄
    if err != nil {
        log.Fatal(err)
    }
    for _, fi := range rd {
        if fi.IsDir() {
            fmt.Printf("[%s]is dir\n", fi.Name())

        } else {
            list = append(list, fi.Name())
            fmt.Println(filepath + fi.Name())
        }
    }
    return list//返回一個string陣列

}

當然也可以普通方式讀入檔名然後用sort包進行排序。
下面是完整程式碼:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "syscall"
)

func movefile(oldpath, newpath string) error { //跨卷移動
    from, err := syscall.UTF16PtrFromString(oldpath)
    if err != nil {
        return err
    }
    to, err := syscall.UTF16PtrFromString(newpath)
    if err != nil {
        return err
    }
    return syscall.MoveFile(from, to)//windows API

}
func filenamelist(filepath string) []string {
    var list []string
    rd, err := ioutil.ReadDir(filepath) //遍歷目錄
    if err != nil {
        log.Fatal(err)
    }
    for _, fi := range rd {
        if fi.IsDir() {
            fmt.Printf("[%s]is dir\n", fi.Name())

        } else {
            list = append(list, fi.Name())
            fmt.Println(filepath + fi.Name())
        }
    }
    return list

}
func movefilelist(oldpath, newpath string) {
    for _, fi := range filenamelist(oldpath) { //移動目錄的所有檔案
        err := movefile(oldpath+fi, newpath+fi)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println(fi + "--Move To -->" + newpath + "--OK!")

    }
}
func main() {
    movefilelist(os.Args[1], os.Args[2])
}

最後在終端中:

[email protected] MINGW64 /Go/test (master)
$ go run main.go ~/Desktop/music/ /d/
C:/Users/Ryan/Desktop/music/新建文字文件 (2).txt
C:/Users/Ryan/Desktop/music/新建文字文件.txt
新建文字文件 (2).txt--Move To -->D:/--OK!
新建文字文件.txt--Move To -->D:/--OK!

有了這個指令碼,我今後終於可以愉快的幫助我外公了。

轉載請註明