title: Golang 遍歷文件及文件夾且計算文件 MD5
date: 2021-06-22 11:04:03
toc: true
category:
- Golang
tags: - Go
- Golang
- 遍歷
- 文件夾
- 子文件
- 計算
- 文件
- MD5
- TODO
2023-4-18 10:58:46
util_file.go 程式碼如下:
package util
import (
"crypto/md5"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
)
// Md5sum 計算文件 MD5 值
func Md5sum(filename string) string {
f, err := os.Open(filename)
if err != nil {
if os.IsNotExist(err) {
return ""
}
return ""
}
defer f.Close()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
return ""
}
return hex.EncodeToString(h.Sum(nil))
}
var firstDir string
// Traverse 遍歷目錄並計算 MD5
func Traverse(dir string) {
// 遍歷目錄
files, err := os.ReadDir(dir)
if err != nil {
panic(err)
}
subDirs := make([]string, 0)
subFiles := make([]string, 0)
// 找到子目錄
for _, f := range files {
if f.IsDir() {
subDirs = append(subDirs, f.Name())
} else {
subFiles = append(subFiles, f.Name())
}
}
// 第一次調用時創建md5sums.txt文件
if firstDir == "" {
firstDir = dir
}
f, err := os.OpenFile(filepath.Join(firstDir, "md5sums.txt"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
if f != nil {
defer f.Close()
}
done := make(chan struct{})
go func() {
// 遍歷子目錄
for _, subDir := range subDirs {
dirPath := filepath.Join(dir, subDir)
Traverse(dirPath)
}
close(done)
}()
go func() {
// 計算文件 MD5
for _, file := range subFiles {
md5FilePath := filepath.Join(dir, file)
md5sum := Md5sum(md5FilePath)
if md5sum != "" {
if f != nil {
_, err := fmt.Fprintf(f, "%s %s\n", md5FilePath, md5sum)
if err != nil {
f, err = os.OpenFile(filepath.Join(firstDir, "md5sums.txt"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
panic(err)
}
defer f.Close()
_, err = fmt.Fprintf(f, "%s %s\n", md5FilePath, md5sum)
if err != nil {
panic(err)
}
}
}
}
}
<-done
}()
<-done
}
util_file_test.go 程式碼如下:
package util
import (
"testing"
)
func TestTraverse(t *testing.T) {
strings := []string{
"D:\\Workspace\\Project\\tank",
"D:\\Workspace\\Project\\recipes",
}
for _, tt := range strings {
Traverse(tt)
firstDir = ""
}
}
每次調用完 Traverse
方法記得將 firstDir 置為 "",運行後將會得到 md5sums.txt
文件,內容如下:
D:\Workspace\Project\tank\.gitignore 49fc96a8f937b2f0e17ef26a2c3b5da2
D:\Workspace\Project\tank\CHANGELOG aac6fc7d43b53c94e9d2fbc1ecaccc8b
D:\Workspace\Project\tank\.git\FETCH_HEAD f42e34d4aa0b4539e4e0f1c4d812a789
D:\Workspace\Project\tank\Dockerfile be292ab456a0b6f3a6d97dff28fd999b
D:\Workspace\Project\tank\.git\HEAD 4cf2d64e44205fe628ddd534e1151b58
D:\Workspace\Project\tank\LICENSE 7ada4a1c6456fbe950cf08d5d82a2c05
D:\Workspace\Project\tank\.git\hooks\applypatch-msg.sample ce562e08d8098926a3862fc6e7905199
D:\Workspace\Project\tank\.git\config a93576437c6e4c8d791a49a8a38a6d53
D:\Workspace\Project\tank\README.md 6a04e351df08269daa708ddee0b47d03
D:\Workspace\Project\tank\.git\description a0a7c3fff21f2aea3cfa1d0316dd816c
D:\Workspace\Project\tank\SECURITY.md b97f0ae5c5e07ecee29db97d36e231d6
D:\Workspace\Project\tank\.git\info\exclude 036208b4a1ab4a235d75c181e685e5a3
D:\Workspace\Project\tank\.git\hooks\commit-msg.sample 579a3c1e12a1e74a98169175fb913012
D:\Workspace\Project\tank\go.mod 633f20ff9d99ad09001926fdef82199f
D:\Workspace\Project\tank\.git\index ea9612a5425e5c79b67aaca64f67336d
D:\Workspace\Project\tank\.git\hooks\fsmonitor-watchman.sample a0b2633a2c8e97501610bd3f73da66fc
D:\Workspace\Project\tank\go.sum 33383355cd8477ac436c892c3347e81b
D:\Workspace\Project\tank\main.go 6aa0980ae206e9ad3396095b3cf36d7f
D:\Workspace\Project\tank\.git\hooks\post-update.sample 2b7ea5cee3c49ff53d41e00785eb974c
D:\Workspace\Project\tank\.git\logs\HEAD 7a96c79d1f5c016b99a1c800092a81a3
D:\Workspace\Project\tank\.git\packed-refs d373a80b5aaf8519f93b9ec52a2c6fee
D:\Workspace\Project\tank\.git\hooks\pre-applypatch.sample 054f9ffb8bfe04a599751cc757226dda
D:\Workspace\Project\tank\.git\logs\refs\heads\master 7a96c79d1f5c016b99a1c800092a81a3
D:\Workspace\Project\tank\.git\hooks\pre-commit.sample 305eadbbcd6f6d2567e033ad12aabbc4
D:\Workspace\Project\tank\.git\hooks\pre-merge-commit.sample 39cb268e2a85d436b9eb6f47614c3cbc
D:\Workspace\Project\tank\.git\logs\refs\remotes\origin\HEAD 7a96c79d1f5c016b99a1c800092a81a3
D:\Workspace\Project\tank\.git\hooks\pre-push.sample 2c642152299a94e05ea26eae11993b13
D:\Workspace\Project\tank\.git\hooks\pre-rebase.sample 56e45f2bcbc8226d2b4200f7c46371bf
D:\Workspace\Project\tank\.git\hooks\pre-receive.sample 2ad18ec82c20af7b5926ed9cea6aeedd
D:\Workspace\Project\tank\.git\hooks\prepare-commit-msg.sample 2b5c047bdb474555e1787db32b2d2fc5
D:\Workspace\Project\tank\.git\hooks\push-to-checkout.sample c7ab00c7784efeadad3ae9b228d4b4db
D:\Workspace\Project\tank\.git\hooks\update.sample 647ae13c682f7827c22f5fc08a03674e
D:\Workspace\Project\tank\.git\objects\pack\pack-da1bb5783cc0c2b96e3487d1b53aeff29dc1b8fe.idx abb79a9f95068aea661df09e4b992978
D:\Workspace\Project\tank\.git\refs\heads\master 0c07035bb5e03adc1fcef252a8a8989e
D:\Workspace\Project\tank\.git\refs\remotes\origin\HEAD 73a00957034783b7b5c8294c54cd3e12
D:\Workspace\Project\tank\.idea\.gitignore c38cf56f115e0ff9f543292d96369362
D:\Workspace\Project\tank\.idea\modules.xml 1201756a21ff0cb151592c0b1ae7a88e
D:\Workspace\Project\tank\.idea\tank.iml 4e17da5ade7136eab5a48dcc6e2766bc
D:\Workspace\Project\tank\.idea\vcs.xml 74d3a64f52848d5e8db631b1685e58c8
D:\Workspace\Project\tank\build\conf\tank.json f55032366878a69a92bd300b7307849e
D:\Workspace\Project\tank\.idea\workspace.xml 9bc3f9591c6d2817852f6b460c88c7dd
D:\Workspace\Project\tank\build\doc\sql\schema-3.1.0.sql 1d5889383091fda14ac1b484f31407bf
D:\Workspace\Project\tank\build\doc\img\dingding.jpg f0d9624f2c0e2425fac91302ede56c70
D:\Workspace\Project\tank\build\html\asset-manifest.json 579aca455fc66af5e9b6e91b6bd36f19
D:\Workspace\Project\tank\build\html\favicon.ico b877eb456647ebce0f190eee1bbf7c38
D:\Workspace\Project\tank\build\doc\img\jb_beam.png e521a96f220daabd14d6316a2a53574d
D:\Workspace\Project\tank\build\html\index.html 58a97885555a967f61be84aef9bf5be2
D:\Workspace\Project\tank\build\doc\img\login.png b937c8971eb013d484984937011fa1be
D:\Workspace\Project\tank\build\doc\img\logo.png 21458adb4d8cc0f1f6b4ee85b5a10f91
D:\Workspace\Project\tank\build\html\static\media\archive.684c1e42f233aa9d53a8910d4fee091e.svg 77d78eb7f0a09aefee1f95f08411be46
D:\Workspace\Project\tank\build\html\static\media\audio.e7112b210bfaa8d0a2ab69f74a66eea4.svg 30a1ea0240c7d661749676da6b67f88e
D:\Workspace\Project\tank\build\doc\img\matters.png e89c86237e2a65364566a95beff8fece
D:\Workspace\Project\tank\build\html\static\css\main.b03c51fb.css 4dd38d8fb3d78f529102f2aded376bbb
D:\Workspace\Project\tank\build\html\static\media\default-skin.f64c3af3d0d25b9e4e00.svg b257fa9c5ac8c515ac4d77a667ce2943
D:\Workspace\Project\tank\build\pack\build.bat ead8dee4dc8e14f6cecddd8ade3481e3
D:\Workspace\Project\tank\build\html\static\media\doc.01619bc74278a86447e699223663ad64.svg 1e70a87cbcfdd0396f2108aa45daf0df
D:\Workspace\Project\tank\build\pack\build.sh d59542f1589456fb032feb8c9a561ce3
D:\Workspace\Project\tank\build\service\shutdown.sh 49be7f9e77de83fc95f095bb4846b779
D:\Workspace\Project\tank\build\service\startup.sh b96ea7c0cf1b53ed018a216296903eac
D:\Workspace\Project\tank\build\html\static\media\empty.20ceb38d310075aa4c3cdaae210afb65.svg babf4d0801025493697c945389bb2e68
D:\Workspace\Project\tank\build\doc\img\mobile.png 559c1603691d29dab8dd0aff989f7cc7
D:\Workspace\Project\tank\build\service\tank.service 2f7ffb530ffca63b446a48cab68e829f
D:\Workspace\Project\tank\build\html\static\media\file.074f42545edfc31c849bdddb013ad8b2.svg fd3e15f8a714653c3005a2773cd00b15
D:\Workspace\Project\tank\code\core\application.go 56a72aae86753c102e55df7ee853f491
D:\Workspace\Project\tank\code\core\bean.go e61a11f80de35dd18244406057bfdde6
D:\Workspace\Project\tank\build\html\static\media\folder.0bdd7430280c98bf4970b6af5a061c2c.svg f8d1b5009857e24890a42c866bbfe925
D:\Workspace\Project\tank\build\doc\img\tank0.png 6faf822f8ea5fcd6eb2058c5bb16979c
D:\Workspace\Project\tank\code\core\config.go 82ca84d9d00524869ed07bcb2962c819
D:\Workspace\Project\tank\build\html\static\media\image.7660bae05269b3c8f2cdf669f04aef3b.svg 06f036cece1ba8775007f41d6d22933c
D:\Workspace\Project\tank\code\core\context.go 45c5229bd7280d55a7255bd0f04a3ae9
D:\Workspace\Project\tank\code\core\controller.go 00f43aef2e5cc91ad101009ab71497e9
D:\Workspace\Project\tank\code\core\global.go 8beb1b3d9944b29cdaa062e1da952898
D:\Workspace\Project\tank\build\doc\img\tank1.png b4874671b95ed486c50fef665a632aac
D:\Workspace\Project\tank\code\core\handler.go 400a3ede0795860897af7bb29bf19c84
D:\Workspace\Project\tank\code\core\logger.go 58cb440c0d808416517db90b267249b9
D:\Workspace\Project\tank\build\html\static\media\logo.847e54ef7fb4b744fad4.png 21458adb4d8cc0f1f6b4ee85b5a10f91
D:\Workspace\Project\tank\build\html\static\media\pdf.eba1e4d316279fc69682dabae6fe6fa4.svg c256fdcbab556414dd550c6c5c5e568d
D:\Workspace\Project\tank\build\doc\img\tank2.png c48dd237ff6b20b4bd7da018fd9f05a4
D:\Workspace\Project\tank\build\html\static\media\ppt.7dc0cfc7fdf0e6f66fb94c81fb34575f.svg 9ec3e0182feb8729760dad76c4e3378d
D:\Workspace\Project\tank\code\rest\alien_controller.go 3d7e1617e951b061b194cb225ac8786e
D:\Workspace\Project\tank\code\rest\alien_service.go 105140018be0a3d2b0dfa9084fa882cd
D:\Workspace\Project\tank\build\html\static\media\psd.bf2ac5411c0132f292787f45855934f2.svg be6691be501376640a7c1e1dd678b2a8
D:\Workspace\Project\tank\code\rest\base_bean.go 5cc49e1a3f839306e631e5bc156d2a90
D:\Workspace\Project\tank\build\html\static\css\main.b03c51fb.css.map 86831daa160f415f62f10344abaf3a62
D:\Workspace\Project\tank\code\support\tank_application.go f0664a9c8d323a13fcf055c57fee8bea
D:\Workspace\Project\tank\build\html\static\media\text.8000463985257af8534ee29db23e1006.svg 49dc13ae6f6d73ab9bdb3969eee980fa
D:\Workspace\Project\tank\code\support\tank_config.go 61ff9ae0fac14361b97f3817b8bd7d8d
D:\Workspace\Project\tank\code\test\cron_test.go 7abb091d0291e68b7234386749e09ed4
D:\Workspace\Project\tank\code\rest\base_controller.go da97f9999930d7c02b93e880c50e51b7
D:\Workspace\Project\tank\code\rest\base_dao.go c3240865f64c1cf05bfdea8677b6aaac
D:\Workspace\Project\tank\build\html\static\media\video.adecb1d58a645ca8d1b1bffad4dbe777.svg 4387235d573fc92ce361822a3306e532
D:\Workspace\Project\tank\code\test\dav_test.go 026d66fb401e2b4b56f417001ba9592f
D:\Workspace\Project\tank\code\support\tank_context.go 3db15d8780e8f99650d417329d825471
D:\Workspace\Project\tank\code\rest\base_model.go 3fe82ffc844c59ea8777597345757a56
D:\Workspace\Project\tank\build\html\static\media\xls.02895077484083ddc5346ab720cd8d1b.svg ef5ba31bd69bdb3c3aec2db584781e53
D:\Workspace\Project\tank\code\test\main_test.go ee1900719a6287f6e59240801ae2c082
D:\Workspace\Project\tank\code\tool\builder\sql_builder.go 38c898f5c4a4115ddeec40804b755dd2
D:\Workspace\Project\tank\code\support\tank_logger.go 72443b6f10adce303a183cd873358887
D:\Workspace\Project\tank\code\test\regex_test.go 6c870912841c7a6e6b6b9dc2435f899a
D:\Workspace\Project\tank\code\rest\bridge_dao.go 145c5a488eb0b807e0b8c2d9d9505c15
D:\Workspace\Project\tank\code\support\tank_router.go 600c1e14d4c7b1595f35ca142a08d5f2
D:\Workspace\Project\tank\code\rest\bridge_model.go ff5bb18ea913e56056016e0a9ff3da4e
D:\Workspace\Project\tank\code\rest\bridge_service.go f25d43999464fd11d4368361d111ff32
D:\Workspace\Project\tank\build\html\static\js\main.b94b1947.js 296b8fb99f71841380aa6d39d4ee1ac8
D:\Workspace\Project\tank\code\tool\cache\cache.go cb22bf27dae4519b86cbb870af2069d7
D:\Workspace\Project\tank\code\rest\dashboard_controller.go 4dff797e27e5cb50bad4478d0fe3d546
D:\Workspace\Project\tank\build\html\static\js\main.b94b1947.js.LICENSE.txt fa06b6e6cc838461959613646cdb63e1
D:\Workspace\Project\tank\code\tool\dav\prop.go 057d6853f03d02c78a4527839b605b0b
D:\Workspace\Project\tank\code\rest\dashboard_dao.go 11511ea8f0fa6cc584961ce4f3cbf62a
D:\Workspace\Project\tank\code\tool\dav\xml\marshal.go 6f21231692ccbbdd82ad7613bbb7ff0e
D:\Workspace\Project\tank\code\rest\dashboard_model.go 5afbe41db5b625b810e74665633201c6
D:\Workspace\Project\tank\code\tool\download\download.go f0b296033489c43fa46f8d9790650195
D:\Workspace\Project\tank\code\tool\i18n\i18n.go 2107e89333a2ec94eb5905fa23b7b997
D:\Workspace\Project\tank\code\rest\dashboard_service.go f8950c81c3798436d786b0c22668301f
D:\Workspace\Project\tank\code\tool\dav\xml\read.go 810e2f3526d47dd896f6a2497db6e60d
D:\Workspace\Project\tank\code\tool\third\gorm_helper.go e283e9ad6f4ba7e29194a17a0afb246f
D:\Workspace\Project\tank\code\rest\dav_controller.go 9748f516a3c25292d6a92c4a11774ae3
D:\Workspace\Project\tank\code\tool\result\web_result.go c67a8d9a6387747a50fe781885e34ea0
D:\Workspace\Project\tank\code\tool\dav\xml\typeinfo.go f49d26205571fef418e96d4ec7155206
D:\Workspace\Project\tank\code\tool\util\util_cron.go d6041d978925a24483417d57ae43a013
D:\Workspace\Project\tank\code\tool\util\util_encode.go 28addf000b3645d356be4dec25de8fe0
D:\Workspace\Project\tank\code\rest\dav_model.go 4d8bd025bbc691e5b85e720b7564978d
D:\Workspace\Project\tank\code\tool\uuid\example_test.go fed13256b8f33a18b2200eac4f40da70
D:\Workspace\Project\tank\code\tool\util\util_env.go ce8da9d0ce13f673aa5cfa7f091fd3ee
D:\Workspace\Project\tank\code\rest\dav_service.go c6b8a4333407d3bb4a924b0115c7a7ea
D:\Workspace\Project\tank\code\tool\dav\xml\xml.go c1a5eccf3b23017fec1b729823f2857f
D:\Workspace\Project\tank\code\tool\uuid\uuid.go b5cb9f4ceedd658dc5783dd38ed16d3e
D:\Workspace\Project\tank\code\tool\util\util_file.go bb3603d3ae00a9c8662f1fb33e5b6656
D:\Workspace\Project\tank\code\rest\download_token_dao.go 3e4ab3383f3852dd809d93d21000dd1e
D:\Workspace\Project\tank\code\tool\uuid\uuid_test.go 01d7d8be9dc952832e258309ea077f3b
D:\Workspace\Project\tank\code\tool\util\util_mime.go 6f45d68c3384f057ecf775e5db74b75a
D:\Workspace\Project\tank\code\tool\webdav\file.go 9fbfad90449993cd0aa9b3e31ea4accb
D:\Workspace\Project\tank\code\rest\download_token_model.go e7990f279c6074ea43be2e1e7159f352
D:\Workspace\Project\tank\code\tool\util\util_network.go 145f4c79c6127a7fe7301b2e13abaa20
D:\Workspace\Project\tank\code\rest\footprint_controller.go 922336f6a629fe42cf1ff79472994834
D:\Workspace\Project\tank\code\tool\webdav\file_test.go ca35d4a0a1e485071f464bbca43a5db2
D:\Workspace\Project\tank\code\tool\util\util_string.go 644d70162016497596269fa144d1a771
D:\Workspace\Project\tank\code\rest\footprint_dao.go 786e362ef15bb8b2db8b66c1aa65094e
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\README d2ea35435e6c409f0bfb14120b8e4123
D:\Workspace\Project\tank\code\tool\util\util_time.go 3b6f8c1b97d1eaa64150f136e9f17f5f
D:\Workspace\Project\tank\code\tool\util\util_validation.go dcedd3cc89e9ee9167717689e6617ec9
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\atom_test.go 3531cf62a00e60517c50143db83df99e
D:\Workspace\Project\tank\code\rest\footprint_model.go f7f4ddaa32b4a9c6a000d7f607b7eb83
D:\Workspace\Project\tank\code\tool\util\util_zip.go 1a6a51aeae944b24261eb14eb3220468
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\example_test.go 97ac04a4cb5b4f7fa52da7a3ee90f599
D:\Workspace\Project\tank\code\rest\footprint_service.go c6fd77d5fe6ef73a3f11630ab78e9f10
D:\Workspace\Project\tank\code\rest\image_cache_controller.go ebd6a7a120bc629bb4f57a822880cdc5
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\marshal.go 6f21231692ccbbdd82ad7613bbb7ff0e
D:\Workspace\Project\tank\code\rest\image_cache_dao.go 64042f9beceb56b72a8f362163bbfc5b
D:\Workspace\Project\tank\code\rest\image_cache_model.go 115d11e2b192b2c66144be1612a12212
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\marshal_test.go 47018de89271131915d31051eaa008cb
D:\Workspace\Project\tank\code\rest\image_cache_service.go 036c16fc04431f88500cc73a9b58e7e4
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\read.go 810e2f3526d47dd896f6a2497db6e60d
D:\Workspace\Project\tank\code\rest\install_controller.go 2b80d6761355495761b7827a997da59f
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\read_test.go 40e71534d582ba706b5cffdc131dbd3a
D:\Workspace\Project\tank\code\rest\install_model.go 1028764ca5db8d44ed15382e9d6dba30
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\typeinfo.go f49d26205571fef418e96d4ec7155206
D:\Workspace\Project\tank\code\rest\matter_controller.go 59338e8dbd267f6a56e35bc589f7f4f7
D:\Workspace\Project\tank\code\rest\matter_dao.go 86fffdc193720b5dedbfed5bd200cfbb
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\xml.go c1a5eccf3b23017fec1b729823f2857f
D:\Workspace\Project\tank\code\tool\webdav\internal\xml\xml_test.go b9ff8d72b4a1f9fe44f45d31ed4ab6fc
D:\Workspace\Project\tank\code\rest\matter_model.go e67268f3ebc574e945a6835711d628c4
D:\Workspace\Project\tank\code\rest\matter_service.go 411ecbeb5c936410c082c18b87ae88ee
D:\Workspace\Project\tank\code\rest\preference_controller.go ae97f1719449feab5756216c809e2da0
D:\Workspace\Project\tank\code\rest\preference_dao.go 4635d9a166bdc748c5d73f8c70497221
D:\Workspace\Project\tank\code\rest\preference_model.go bb4f6a088f3665eebd40f60206e7866f
D:\Workspace\Project\tank\code\rest\preference_service.go 99331aa2a973247d00dfe845fee613ad
D:\Workspace\Project\tank\code\rest\session_dao.go d05e8b32e16680e0940a5a0813a8131f
D:\Workspace\Project\tank\code\rest\session_model.go f96a3d337847389badeff9336e9435dd
D:\Workspace\Project\tank\code\rest\session_service.go fd5b721cd2cc71c74216c328afeceb28
D:\Workspace\Project\tank\code\rest\share_controller.go 2e75ea5f956cf57224b00269d3077af5
D:\Workspace\Project\tank\code\rest\share_dao.go c8c06d573d0969f8141132507940a8d2
D:\Workspace\Project\tank\code\rest\share_model.go 4331a49721e0d4aa483a84beaa6014fb
D:\Workspace\Project\tank\code\rest\share_service.go 2689b62a6bca666fdf2626d751ccdce7
D:\Workspace\Project\tank\code\rest\task_service.go 583eecfe9e2a9642d5add0df13f4f90f
D:\Workspace\Project\tank\code\rest\upload_token_dao.go a424cf6fcff75746defa57218b80d14a
D:\Workspace\Project\tank\code\rest\upload_token_model.go 32684782791c81b3861f5b849a5cb95a
D:\Workspace\Project\tank\code\rest\user_controller.go f59c53094a6425392ec9900c449b145f
D:\Workspace\Project\tank\code\rest\user_dao.go 854bd4552474e22afa7ba30047aed5d1
D:\Workspace\Project\tank\code\rest\user_model.go ebe2f447c944b611d04e6d543bb53612
D:\Workspace\Project\tank\code\rest\user_service.go 6edba6a1e01c62d41dbe1d00927c2f20
D:\Workspace\Project\tank\build\html\static\js\main.b94b1947.js.map d054db641badfc68a620cf3b5f0db4f9
D:\Workspace\Project\tank\.git\objects\pack\pack-da1bb5783cc0c2b96e3487d1b53aeff29dc1b8fe.pack 1f769c77b88461967111b739e399adfe
2022 年 6 月 30 日 14 點 06 更新程式碼
package main
import (
"bufio"
"crypto/md5"
"fmt"
"io"
"os"
"path/filepath"
"sync"
"time"
)
/*
1. 讀取文件列表
2. 並發計算文件md5
3. 等待計算完畢將數據打印
*/
func main() {
startTime := time.Now()
var wg sync.WaitGroup
workers, err := readDirAllFiles("C:\\Users\\Administrator\\Downloads\\SM\\2022\\01\\01", &wg)
// workers, err := readDirAllFiles("C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Windsys 工具箱", &wg)
// workers, err := readDirAllFiles("C:\\Users\\Administrator\\Downloads\\.accelerate", &wg)
// workers, err := readDirAllFiles("C:\\Users\\Administrator\\Downloads", &wg)
if err != nil {
panic(err)
}
var result []FileInfo
for _, v := range workers {
result = append(result, <-v.out)
}
fmt.Println(len(result), "總耗時", time.Since(startTime))
wg.Wait()
}
func createWorker(id int, wg *sync.WaitGroup) worker {
w := worker{
in: make(chan FileReceiveInfo),
out: make(chan FileInfo),
done: wg.Done,
}
go doWork(id, w)
return w
}
func doWork(id int, w worker) {
defer w.done()
receiveInfo := <-w.in
fmt.Printf("No.%-7d worker receive path: %v, size: %v\n", id, receiveInfo.FilePath, receiveInfo.FileSize)
startMd5CalcTime := time.Now()
fileMd5, err := MD5sum(receiveInfo.FilePath)
fmt.Printf("No.%-7d worker time: %v\n", id, time.Since(startMd5CalcTime))
if err != nil {
fmt.Printf("file [%s] has error: %v\n", receiveInfo.FilePath, err)
}
w.out <- FileInfo{
FilePath: receiveInfo.FilePath,
FileMd5: fileMd5,
}
}
type worker struct {
in chan FileReceiveInfo
out chan FileInfo
done func()
}
type FileReceiveInfo struct {
FilePath string
FileSize int64
}
// 讀取指定目錄下的所有文件
func readDirAllFiles(rootPath string, wg *sync.WaitGroup) ([]worker, error) {
var workers []worker
dirEntries, err := os.ReadDir(rootPath)
if err != nil {
return nil, err
}
wg.Add(len(dirEntries))
for i, dirEntry := range dirEntries {
if !dirEntry.IsDir() {
worker := createWorker(i, wg)
workers = append(workers, worker)
entryPath := filepath.Join(rootPath, dirEntry.Name())
fileInfo, _ := dirEntry.Info()
worker.in <- FileReceiveInfo{
FilePath: entryPath,
FileSize: fileInfo.Size(),
}
}
}
return workers, nil
}
const bufferSize = 65536
// MD5sum returns MD5 checksum of filename
func MD5sum(filename string) (string, error) {
if info, err := os.Stat(filename); err != nil {
return "", err
} else if info.IsDir() {
return "", nil
}
file, err := os.Open(filename)
if err != nil {
return "", err
}
defer file.Close()
hash := md5.New()
for buf, reader := make([]byte, bufferSize), bufio.NewReader(file); ; {
n, err := reader.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return "", err
}
hash.Write(buf[:n])
}
checksum := fmt.Sprintf("%x", hash.Sum(nil))
return checksum, nil
}
2022 年 6 月 28 日 11 點 28 分更新程式碼
Fix:程式遇到無權限或其他錯誤時會直接退出,改為輸出錯誤,處理下一個文件 / 文件夾
package main
import (
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"sync"
"time"
)
var (
rootDir = "C:\\Users\\Administrator\\Downloads\\SM\\2016\\03\\19"
// rootDir = "C:\\Users\\Administrator\\Downloads"
)
/*
Ref: [Go語言並發模型:以並行處理MD5為例 - SegmentFault 思否](https://segmentfault.com/a/1190000006670880)
*/
func main() {
startTime := time.Now()
rootPath := os.Args[1]
fmt.Println("計算目錄", rootPath)
// 等待動畫
go spinner(250 * time.Millisecond)
// 計算特定目錄下所有文件的 md5值
// 然後按照路徑名順序打印結果
m, err := MD5All(rootPath)
if err != nil {
fmt.Printf("\r%v\n", err)
return
}
var paths []string
for path := range m {
paths = append(paths, path)
}
sort.Strings(paths)
result := make(map[string]string, len(paths))
for _, path := range paths {
// fmt.Printf("%x %s\n", m[path], path)
result[path] = fmt.Sprintf("%x", m[path])
}
fmt.Println("\r總耗時", time.Since(startTime), "總文件", len(result))
marshal, _ := json.MarshalIndent(result, "", " ")
writeRelFile(rootPath, marshal)
}
func writeRelFile(rootPath string, marshal []byte) {
writeFilePath := filepath.Join(rootPath, "marshal.json")
err := ioutil.WriteFile(writeFilePath, marshal, 0755)
if err != nil {
dir, errwd := os.Getwd()
if errwd != nil {
fmt.Printf("\r獲取程式所在目錄出錯:%v\n", errwd)
return
}
if dir == rootPath {
fmt.Println("\r當前文件所在目錄無權限,請切換目錄後執行")
return
}
fmt.Printf("\r寫入映射文件出錯:%v,嘗試寫入到程式所在目錄:%s\n", err, dir)
writeRelFile(dir, marshal)
return
}
fmt.Printf("\r映射文件已保存至【%s】目錄。\n", writeFilePath)
}
func spinner(delay time.Duration) {
for {
for _, r := range `-\|/` {
fmt.Printf("\r%c", r)
time.Sleep(delay)
}
}
}
/*並發版 Start*/
type result struct {
path string
sum [md5.Size]byte
err error
}
func sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan error) {
// 對於每一個普通文件,啟動一個 gorotuine 計算文件 md5 值,
// 然後 將結果發送到 c。
// walk 的錯誤結果發送到 errc。
c := make(chan result)
errc := make(chan error, 1)
go func() {
var wg sync.WaitGroup
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("\rwalk has panic: %v\n", err)
return filepath.SkipDir
}
if !info.Mode().IsRegular() {
return nil
}
wg.Add(1)
go func() {
data, err := ioutil.ReadFile(path)
select {
case c <- result{path, md5.Sum(data), err}:
case <-done:
}
wg.Done()
}()
// done channel 關閉時,終止 walk 函數
select {
case <-done:
return errors.New("walk canceled")
default:
return nil
}
})
// Walk 函數已經返回,所以 所有對 wg.Add 的調用都會結束
// 啟動一個 goroutine, 它會在所有發送都結束時,關閉 c。
go func() {
wg.Wait()
close(c)
}()
// 這裡不需要 select 語句,應為 errc 是緩衝管道
errc <- err
}()
return c, errc
}
func MD5All(root string) (map[string][md5.Size]byte, error) {
// MD5All 在函數返回時關閉 done channel
// 在從 c 和 errc 接收數據前,也可能關閉
done := make(chan struct{})
defer close(done)
c, errc := sumFiles(done, root)
m := make(map[string][md5.Size]byte)
for r := range c {
if r.err != nil {
return nil, fmt.Errorf("code in 138 has panic: %v", r.err)
}
m[r.path] = r.sum
}
if err := <-errc; err != nil {
return nil, fmt.Errorf("code in 143 has panic: %v", err)
}
return m, nil
}
/*並發版 End*/
// ----------------------------------------- 分割線 -----------------------------------------
/*非並發版 Start*/
// MD5All 讀取 root 目錄下的所有文件,返回一個map
// 該 map 存儲了 文件路徑到文件內容 md5值的映射
// 如果 Walk 執行失敗,或者 ioutil.ReadFile 讀取失敗,
// MD5All 都會返回錯誤
func MD5AllOld(root string) (map[string][md5.Size]byte, error) {
m := make(map[string][md5.Size]byte)
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
m[path] = md5.Sum(data)
return nil
})
if err != nil {
return nil, err
}
return m, nil
}
/*非並發版 End*/
2022 年 6 月 27 日 10 點 09 分更新程式碼
package main
import (
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"sync"
"time"
)
var (
// rootDir = "C:\\Users\\Administrator\\Downloads\\SM\\2016\\03\\19"
rootDir = "C:\\Users\\Administrator\\Downloads"
)
/*
Ref: [Go語言並發模型:以並行處理MD5為例 - SegmentFault 思否](https://segmentfault.com/a/1190000006670880)
*/
func main() {
startTime := time.Now()
// 等待動畫
go spinner(100 * time.Millisecond)
// 計算特定目錄下所有文件的 md5值
// 然後按照路徑名順序打印結果
m, err := MD5All(rootDir)
if err != nil {
fmt.Println(err)
return
}
var paths []string
for path := range m {
paths = append(paths, path)
}
sort.Strings(paths)
result := make(map[string]string, len(paths))
for _, path := range paths {
// fmt.Printf("%x %s\n", m[path], path)
result[path] = fmt.Sprintf("%x", m[path])
}
fmt.Println("\r總耗時", time.Now().Sub(startTime))
marshal, _ := json.MarshalIndent(result, "", " ")
writeFilePath := filepath.Join(rootDir, "marshal.json")
err = ioutil.WriteFile(writeFilePath, marshal, 0755)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("\r映射文件已保存至【%s】目錄。\n", writeFilePath)
}
func spinner(delay time.Duration) {
for {
for _, r := range `-\|/` {
fmt.Printf("\r%c", r)
time.Sleep(delay)
}
}
}
/*並發版 Start*/
type result struct {
path string
sum [md5.Size]byte
err error
}
func sumFiles(done <-chan struct{}, root string) (<-chan result, <-chan error) {
// 對於每一個普通文件,啟動一個 gorotuine 計算文件 md5 值,
// 然後 將結果發送到 c。
// walk 的錯誤結果發送到 errc。
c := make(chan result)
errc := make(chan error, 1)
go func() {
var wg sync.WaitGroup
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
wg.Add(1)
go func() {
data, err := ioutil.ReadFile(path)
select {
case c <- result{path, md5.Sum(data), err}:
case <-done:
}
wg.Done()
}()
// done channel 關閉時,終止 walk 函數
select {
case <-done:
return errors.New("walk canceled")
default:
return nil
}
})
// Walk 函數已經返回,所以 所有對 wg.Add 的調用都會結束
// 啟動一個 goroutine, 它會在所有發送都結束時,關閉 c。
go func() {
wg.Wait()
close(c)
}()
// 這裡不需要 select 語句,應為 errc 是緩衝管道
errc <- err
}()
return c, errc
}
func MD5All(root string) (map[string][md5.Size]byte, error) {
// MD5All 在函數返回時關閉 done channel
// 在從 c 和 errc 接收數據前,也可能關閉
done := make(chan struct{})
defer close(done)
c, errc := sumFiles(done, root)
m := make(map[string][md5.Size]byte)
for r := range c {
if r.err != nil {
return nil, r.err
}
m[r.path] = r.sum
}
if err := <-errc; err != nil {
return nil, err
}
return m, nil
}
/*並發版 End*/
// ----------------------------------------- 分割線 -----------------------------------------
/*非並發版 Start*/
// MD5All 讀取 root 目錄下的所有文件,返回一個map
// 該 map 存儲了 文件路徑到文件內容 md5值的映射
// 如果 Walk 執行失敗,或者 ioutil.ReadFile 讀取失敗,
// MD5All 都會返回錯誤
func MD5AllOld(root string) (map[string][md5.Size]byte, error) {
m := make(map[string][md5.Size]byte)
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.Mode().IsRegular() {
return nil
}
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
m[path] = md5.Sum(data)
return nil
})
if err != nil {
return nil, err
}
return m, nil
}
/*非並發版 End*/