Swift - 移动或更新文件失败
Posted
技术标签:
【中文标题】Swift - 移动或更新文件失败【英文标题】:Swift - Move or update file fails 【发布时间】:2017-12-04 16:19:22 【问题描述】:我正在使用我的 Swift ios 应用下载大量文件,并且我对我的内容使用增量更新。
我的下载代码非常基础,我使用 Alamofire 将一个文件下载到一个临时目录中,解压缩,检查目标目录中是否存在该文件或文件夹,如果找到则将其删除,然后移动新的文件/文件夹到那个目录。
但在检查现有目录并将其删除后很少出现问题。当我尝试将新的 文件/文件夹 移动到该目录时,出现
错误“文件或目录已存在或内容不为空。”
但是在设备目录中失败后检查它,它显示一个完全正常的目录,没有可能发生冲突的现有文件,或者有时新内容确实像它应该的那样移动到目标目录,即使它说失败.这是最困扰我的。
有没有人在目录中保存和移动文件时有过这种行为?
我差点忘了,我在应用程序支持目录中工作。
internal func loadArtifact(artifact: Artifact, updateClosure: @escaping ((Bool, Int64, Int64, String?) -> ()))
let serverpath = artifact.serverpath
let name = artifact.name
let zipname = artifact.zipname
let root = artifact.artifactSetroot
let hidden = artifact.artifactSet!.hidden
let objectID = artifact.objectID
let baseArtifactSet = artifactSetManager.defaultartifactSetManager.getartifactSetDirectory(artifact.artifactSet!)
if baseArtifactSet == nil
errorLog("No target directory for artifactSet")
return
if name == nil
errorLog("No name for artifact. Can´t save in temp")
return
var targetDirectory = baseArtifactSet
targetDirectory?.appendPathComponent("temp")
targetDirectory?.appendPathComponent(zipname!.replacingOccurrences(of: ".zip", with: ""))
let destination: DownloadRequest.DownloadFileDestination = _, _ in
return (targetDirectory!, [.removePreviousFile, .createIntermediateDirectories])
let url = URL(string: serverpath!)
alamofireManager!.download(url!, to: destination).downloadProgress (progress) in
updateClosure(false, progress.completedUnitCount, progress.completedUnitCount, nil)
.responseData (data) in
traceLog("\(data)")
if data.response?.statusCode == 200
traceLog("Got an artifact. Will continue to extract itto target position")
self.asyncQueue.async
var unzipTarget = baseArtifactSet
SSZipArchive.unzipFile(atPath: targetDirectory!.path, toDestination: root ? "\(unzipTarget!.path)/temp/root" : "\(unzipTarget!.path)/temp", progressHandler: (message, something, progress, max) in
, completionHandler: (message, finished, error) in
let tmpPath = root ? "\(unzipTarget!.path)/temp/root" : "\(unzipTarget!.path)/temp/artifacts/\(zipname!.replacingOccurrences(of: ".zip", with: ""))"
let targetPath = root ? unzipTarget!.path : "\(unzipTarget!.path)/artifacts/\(zipname!.replacingOccurrences(of: ".zip", with: ""))"
if error == nil && root == false && FileManager.default.fileExists(atPath: targetPath)
do
try FileManager.default.removeItem(atPath: targetPath)
traceLog("Deletet old directory at path: \(unzipTarget!.path)")
catch
errorLog("Could not remove directory at path: \(unzipTarget!.path) - \(error)")
updateClosure(true,0,0,"Could not remove directory at path: \(unzipTarget!.path) - \(error)")
do
if FileManager.default.fileExists(atPath: "\(unzipTarget!.path)/artifacts") == false
try FileManager.default.createDirectory(atPath: "\(unzipTarget!.path)/artifacts", withIntermediateDirectories: true, attributes: nil)
if root
do
let targetDirContent = try FileManager.default.contentsOfDirectory(atPath: targetPath)
for file in targetDirContent
if file != "artifacts" && file != "temp"
try FileManager.default.removeItem(atPath: "\(targetPath)/\(file)")
let files = try FileManager.default.contentsOfDirectory(atPath: tmpPath)
for file in files
let fileURL = URL(fileURLWithPath: "\(tmpPath)/\(file)")
if fileURL != nil
try FileManager.default.moveItem(atPath: fileURL.path, toPath: "\(targetPath)/\(file)")
if root && hidden
let deviceInfoString = "var deviceInfo='platform':'iOS'"
if FileManager.default.fileExists(atPath: "\(targetPath)/deviceInfo.js")
try FileManager.default.removeItem(atPath: "\(targetPath)/deviceInfo.js")
catch
errorLog("Error while enumerating files in temp root directory: \(error)")
updateClosure(true,0,0,"Error while enumerating files in temp root directory: \(error)")
else
if FileManager.default.fileExists(atPath: targetPath)
debugLog("Deleting: \(targetPath)")
try FileManager.default.removeItem(atPath: targetPath)
else
debugLog("Creating: \(targetPath)")
debugLog("Trying to move")
try FileManager.default.moveItem(atPath: tmpPath, toPath: targetPath)
catch
errorLog("Could not move directory for artifact: \(unzipTarget!.path) - \(error)")
updateClosure(true,0,0,"Could not move directory for artifact: \(unzipTarget!.path) - \(error)")
try FileManager.default.removeItem(atPath: targetDirectory!.path)
self.asyncQueue.async (flags: .barrier)
let ownContext = MyStorageClient.defaultManager.newBackgroundWorkerMOC()
let ownArtifact = ownContext.object(with: objectID) as! Artifact
ownArtifact.state = ArtifactState.Ready.rawValue
ownArtifact.updateAvaiable = false
if root == true && ownArtifact.artifactSet?.state == artifactSetState.Initialised.rawValue
ownArtifact.artifactSet?.state = artifactSetState.Created.rawValue
do
try ownContext.save()
updateClosure(true, 0,0,nil)
catch
errorLog("Error while saving artifact context")
updateClosure(true, 0,0, "Error while saving context after artifact Update. \(error)")
)
else
errorLog("Something went wrong downloading an artifact: \(data.response)")
updateClosure(true,0,0,"Something went wrong downloading an artifact: \(data.response)")
那么,谁能告诉我,为什么它失败了? 我在大多数尝试行周围添加了do-try-catch,当它失败时,它基本上在这个块上失败了:
if FileManager.default.fileExists(atPath: targetPath)
debugLog("Deleting: \(targetPath)")
try FileManager.default.removeItem(atPath: targetPath)
else
debugLog("Creating: \(targetPath)")
debugLog("Trying to move")
try FileManager.default.moveItem(atPath: tmpPath, toPath: targetPath)
目标路径是: file:///var/mobile/Containers/Data/Application/applicationIdAndStuff/Library/Application%20Support/environment/workspace/customers/customer/temp/downloadFileOrFolder
另一个更新: 我更改了代码,所以旧文件将被移动到备份文件夹而不是立即删除,因为我认为更改地址应该比完全删除文件更快。错误的。现在错误比以前更频繁地发生。
所以对我来说这个问题被提到了 FileManager,它需要很长时间才能完成程序。我真的不想让我的积木进入休眠状态,你对如何处理这个问题有其他想法吗?
【问题讨论】:
能不能把代码少一点,我都懒得看这些了 已更新,在完整代码之上,在问题部分之下。 @Viktor_DE,targetPath
在运行时的值是多少?
@holex 更新了我的问题,信息在底部。
【参考方案1】:
我发现了这个问题,只需将代码排序为所需的>only once tasks和>tasks for each artifact,以减轻文件管理器的压力。
因此,此代码处理每个工件的下载、取消归档和移动过程,它总是检查更高级别的目录是否存在,如果不存在则添加它们。对于每个工件。 因此,当多个下载和取消归档几乎同时完成并开始处理目录内容时,这已经是潜在的冲突了。
然后,为移动文件准备文件夹带来的麻烦多于帮助。 虽然它在大多数情况下都能正常工作,但有时它会扰乱系统检查以移动文件并导致错误告诉我目录或文件已存在。
因此,在获取文件的每个 loadArtifact 之前,我重置了所需的目录并创建了更高级别的目录,以防止循环中的重复检查。
因为一切都像预期的那样工作。
【讨论】:
以上是关于Swift - 移动或更新文件失败的主要内容,如果未能解决你的问题,请参考以下文章