在 mac 上如何使用 xcode, swift 语言开发一个向 ftp 服务器上传文件的工具?
使用的是第三方库 Rebekka,下载地址为:https://github.com/Constantine-Fry/rebekka。下载完之后直接将所有的 swift 文件拷到项目中即可使用。
下面是我自己写的代码 ,首先是 FtpManager.swift 类,封装了上传文件和创建文件夹的方法,代码如下:
// // FtpHelper.swift // MacFtpUploader // // Created by Jie Tian on 23/3/16. // Copyright © 2016 Jie Tian. All rights reserved. // import Foundation public class FtpManager { let m_host:String; let m_username:String; let m_password:String; let m_session:Session; init (host:String,username:String,password:String,passive:Bool) { m_host=host; m_username=username; m_password=password; var config=SessionConfiguration(); config.host=host; config.username=username; config.password=password; config.passive=passive; m_session=Session(configuration: config); } public func UploadFile(srcPath:String,tarPath:String,callback:(Bool) -> Void) { let localPath=NSURL(fileURLWithPath: srcPath); m_session.upload(localPath, path: tarPath) { (succeed,error) -> Void in let fullUrl=self.m_host+tarPath; if succeed { print("Upload succeed! Source path: (localPath) Target url: (fullUrl) "); } else { print("Upload failed... Error: (error) Source path: (localPath) Target url: (fullUrl) "); } callback(succeed); }; } public func CreateDirectory(path:String) { m_session.createDirectory(path) { (succeed, error) -> Void in let url=self.m_host+path; if succeed { print("Create directory succeed! Url: (url) "); } } } }
下面是程序的入口 main.swift,代码如下:
1 // 2 // main.swift 3 // MacFtpUploader 4 // 5 // Created by Jie Tian on 22/3/16. 6 // Copyright © 2016 Jie Tian. All rights reserved. 7 // 8 9 import Foundation 10 11 // 获取 host 所对应的文件夹的 url 12 func GetHostDirUrls(host:String,inout rootHost:String) -> [String] 13 { 14 var urls=[String](); 15 let words=host.characters.split("/"); 16 let w0Str=String(words[0]); 17 let w1Str=String(words[1]); 18 rootHost="(w0Str)//(w1Str)"; 19 20 for i in 2..<words.count 21 { 22 var url:String=String(); 23 for t in 2...i 24 { 25 url+="/"+String(words[t]); 26 } 27 urls.append(url); 28 } 29 30 return urls; 31 } 32 33 // 传入一个根文件夹路径,取得其所有的文件与文件夹路径 34 func GetAllFiles(rootDir:String,inout allDirectories:[String],localRootDirName:String) -> [String] 35 { 36 let manager=NSFileManager.defaultManager(); 37 let url=NSURL(fileURLWithPath: rootDir); 38 let contents=manager.enumeratorAtURL(url, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions.SkipsHiddenFiles, errorHandler: nil); 39 40 var allFiles=[String](); 41 allDirectories=[localRootDirName]; // local root dir name must be created first 42 43 for item in contents! 44 { 45 var isDir:ObjCBool=ObjCBool(false); 46 let exists=manager.fileExistsAtPath(item.path, isDirectory:&isDir); 47 if !exists 48 { 49 continue; 50 } 51 52 if isDir 53 { 54 allDirectories.append(item.path); 55 } 56 else 57 { 58 allFiles.append(item.path); 59 } 60 } 61 62 return allFiles; 63 } 64 65 // 将本地的路径转化为上传的 url 66 func GetUrl(path:String,absolutePath:String,localRootDirName:String) -> String 67 { 68 // 获取 “IOS” 的位置 69 var rightIndex:String.Index? = nil; 70 71 for i in 0..<path.characters.count 72 { 73 if i+localRootDirName.characters.count > path.characters.count 74 { 75 continue; 76 } 77 78 var isRight:Bool=true; 79 80 for k in 0..<localRootDirName.characters.count 81 { 82 let c = path[path.startIndex.advancedBy(i+k)]; 83 let tc = localRootDirName[localRootDirName.startIndex.advancedBy(k)]; 84 if c != tc 85 { 86 isRight = false; 87 break; 88 } 89 } 90 91 if isRight 92 { 93 rightIndex = path.startIndex.advancedBy(i); 94 break; 95 } 96 } 97 98 // 拼接 url 99 return absolutePath+"/"+path.substringFromIndex(rightIndex!); 100 } 101 102 func Upload(host:String,username:String,password:String,path:String,passive:Bool) 103 { 104 print("Start upload: host: (host) username: (username) password: (password) path: (path) passive: (passive) "); 105 106 // 创建host对应的文件夹 107 var rootHost:String=String(); 108 let hostDirUrls=GetHostDirUrls(host,rootHost:&rootHost); 109 let ftp=FtpManager(host:rootHost,username:username,password:password,passive: passive); 110 111 for hu in hostDirUrls 112 { 113 ftp.CreateDirectory(hu); 114 } 115 116 let pathDirs=path.characters.split("/"); 117 let localRootDirName = String(pathDirs.last!); 118 var allDirs:[String]=[String](); 119 let allFiles=GetAllFiles(path, allDirectories: &allDirs,localRootDirName:localRootDirName); 120 121 // 创建本地文件需要的文件夹 122 for dp in allDirs 123 { 124 let dirUrl=GetUrl(dp,absolutePath: hostDirUrls.last!,localRootDirName:localRootDirName); 125 ftp.CreateDirectory(dirUrl); 126 } 127 128 // 上传文件 129 let totalCount=allFiles.count; 130 var uploadedCount=0; 131 132 for fp in allFiles 133 { 134 let fileUrl=GetUrl(fp,absolutePath: hostDirUrls.last!,localRootDirName:localRootDirName); 135 ftp.UploadFile(fp, tarPath: fileUrl) 136 { 137 (succeed) -> Void in 138 if succeed 139 { 140 uploadedCount++; 141 142 if uploadedCount >= totalCount 143 { 144 print(" All files are uploaded to [(host)] succeed!!! "); 145 } 146 } 147 } 148 } 149 } 150 151 // 程序入口 152 func Main() 153 { 154 // let host="ftp://119.15.139.103/TianJie"; 155 // let username="feixiang.tu"; 156 // let password="feixiang.tu"; 157 // let path="/Users/jie.tian/Documents/BleachMaster/FtpBackup/IOS/"; 158 159 // let host="ftp://54.223.59.161/Tian/Jie/"; 160 // let username="bleach"; 161 // let password="8c%2rFnlCh&*7$TQqx#UikX"; 162 // let path="/Users/jie.tian/Documents/BleachMaster/FtpBackup/IOS/"; 163 164 // get arguments first 165 let argFilePath=NSBundle.mainBundle().bundlePath+"/MacFtpUploader_Arguments"; 166 let argFileUrl=NSURL(fileURLWithPath: argFilePath); 167 let argString=try! NSString(contentsOfURL: argFileUrl, encoding: NSUTF8StringEncoding); 168 let argLines=argString.description.characters.split(" "); 169 170 for l in argLines 171 { 172 let str=String(l); 173 let argWords=str.characters.split(","); 174 let host=String(argWords[1]); 175 let username=String(argWords[2]); 176 let password=String(argWords[3]); 177 let path=String(argWords[0]); 178 let passive=String(argWords[4])=="True"; 179 180 // upload 181 Upload(host,username: username,password: password,path: path,passive: passive); 182 } 183 184 // delete temp argFile 185 try! NSFileManager.defaultManager().removeItemAtPath(argFilePath); 186 187 NSRunLoop.mainRunLoop().run(); 188 } 189 190 Main();
此 mac 工具是被 unity3d 的一键打包工具调用的,思路是将 shell 命令写在一个文件中,在 c# 中执行此 shell 文件以打开此工具。
shell 命令为,&1 为工具路径,是c#传过来的值:
#!/bin/bash open $1
调用上面 shell 文件的 c# 代码为:
if (!IsWindowSystem) { string rootPath = string.Format("{0}/Editor/BuildAssetBundle/Tools/", Application.dataPath.TrimEnd('/')); // save arguments to file string tempFilePath = rootPath + "MacFtpUploader_Arguments"; File.WriteAllText(tempFilePath, sb.ToString()); // invoke tool if (File.Exists(tempFilePath)) { string toolPath = rootPath + "MacFtpUploader"; string shell = string.Format("{0}MacFtpUploaderInvoker.sh {1}", rootPath, toolPath); Process.Start("/bin/bash", shell); } else throw new InvalidOperationException(string.Format("Save arguments to file {0} failed, reupload again please...", tempFilePath)); }
运行结果为:
xcode 项目附件如下:
http://files.cnblogs.com/files/jietian331/MacFtpUploader.zip