Golang如何从需认证的SMB共享文件夹直接解压zip文件到本地
解决方案
直接基于go-smb2挂载实例处理(无需预先下载完整zip到本地)
你已经拿到smb2.FS实例之后,可以直接遍历共享目录、读取zip文件内容,通过支持密码解密的纯Go zip库直接将文件解压到本地指定目录,不需要先把整个zip包下载到本地存储。
操作步骤
- 用
fs.WalkDir遍历SMB共享目录,筛选后缀为.zip的文件 - 打开匹配的zip文件获取远程文件流
- 传入文件流到支持密码的zip读取库,逐个将压缩包内的文件写入本地目录
- 解压完成后执行你原有的后续业务逻辑
代码示例
import ( "io" "os" "path/filepath" "strings" // 需引入支持密码解压的zip库 "github.com/yeka/zip" ) // 该函数在你挂载完成拿到fs *smb2.FS实例后调用 func processSMBZip(fs *smb2.FS, localOutputRoot string) error { zipPassword := "your_zip_password" return fs.WalkDir(".", ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } // 跳过目录和非zip文件 if d.IsDir() || filepath.Ext(path) != ".zip" { return nil } // 打开SMB上的zip文件 remoteFile, err := fs.Open(path) if err != nil { return err } defer remoteFile.Close() fileInfo, err := remoteFile.Stat() if err != nil { return err } // 初始化zip读取器 zipReader, err := zip.NewReader(remoteFile, fileInfo.Size()) if err != nil { return err } // 生成本地解压目录 zipName := strings.TrimSuffix(filepath.Base(path), ".zip") localUnzipDir := filepath.Join(localOutputRoot, zipName) if err := os.MkdirAll(localUnzipDir, 0755); err != nil { return err } // 逐个解压文件到本地 for _, zf := range zipReader.File { zf.SetPassword(zipPassword) fileReader, err := zf.Open() if err != nil { return err } defer fileReader.Close() outFilePath := filepath.Join(localUnzipDir, zf.Name) // 处理压缩包内的目录 if zf.FileInfo().IsDir() { os.MkdirAll(outFilePath, zf.Mode()) continue } if err := os.MkdirAll(filepath.Dir(outFilePath), 0755); err != nil { return err } // 写入本地文件 outFile, err := os.Create(outFilePath) if err != nil { return err } _, err = io.Copy(outFile, fileReader) outFile.Close() if err != nil { return err } } // 执行你原有后续逻辑 iterateThroughPE(localUnzipDir) parsePKCS7(localUnzipDir) splitter(start_string, end_string, localUnzipDir) return nil }) }
低改动兼容方案(复用原有unzip命令逻辑)
如果你不想修改原有基于系统unzip命令的解压逻辑,可以先把SMB共享中的zip文件下载到本地临时目录,再调用你原有的extractZipWithPassword函数处理:
// 打开SMB上的zip文件后,写入本地临时目录 localTempDir := "./smb_temp" os.MkdirAll(localTempDir, 0755) tempZipPath := filepath.Join(localTempDir, filepath.Base(path)) tempFile, err := os.Create(tempZipPath) if err != nil { return err } io.Copy(tempFile, remoteFile) tempFile.Close() // 调用原有逻辑处理 extractZipWithPassword(localTempDir, localOutputRoot) // 处理完删除临时文件节省空间 os.Remove(tempZipPath)
可选替代实现路径
如果go-smb2的方案遇到兼容性问题,可以选择以下实现方式:
- 系统级挂载SMB共享:在程序运行的操作系统层面先把SMB共享挂载为本地路径(Linux用
mount.cifs、Windows用net use命令,挂载时传入用户名密码),之后直接把挂载路径作为本地路径传入你原有的extractZipWithPassword函数即可,无需修改任何业务代码 - 调用系统smbclient命令行:通过
exec.Command调用系统自带的smbclient工具下载共享中的zip文件到本地,再执行原有处理逻辑,无需引入第三方Go依赖
内容的提问来源于stack exchange,提问作者dialga19
相关产品推荐
相关产品推荐

