问题
I am developing a zip extractor app i followed the algorithm that CRD explained @Here but i stuck at third step i am unable to rename the unzipped file which is at temporary directorary. here is my code
NSURL *tempDir = [NSURL fileURLWithPath:destinationPath];
NSError *error;
NSURL *tmpDirectory = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:tempDir create:YES error:&error];
if (error) {
return ;
}
tmpDirectory = [tmpDirectory URLByAppendingPathComponent:@"extracts"];
NSLog(@"temp dir %@",tmpDirectory);
NSLog(@"temp path %@",tmpDirectory.path);
[SSZipArchive unzipFileAtPath:zipFilePath toDestination:tmpDirectory.path];
NSArray *dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectory.path error:nil];
NSLog(@"dir file %@",dirFiles);
for (NSString *string in dirFiles) {
NSArray *dirDestinationFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:destinationPath error:nil];
NSLog(@"dir destination file %@",dirDestinationFiles);
[dirDestinationFiles enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error;
if ([string isEqualToString:obj]) {
NSLog(@"Already present");
BOOL isMoved = [fm moveItemAtPath:tmpDirectory.path toPath:[destinationPath stringByAppendingString:[NSString stringWithFormat:@"/%@-1",string]] error:&error];
if (isMoved) {
NSLog(@"Moved");
}else{
NSLog(@"errorL %@", error);
NSLog(@"Not moved");
}
[fm removeItemAtPath:tmpDirectory.path error:&error];
[self moveFileToTrash:zipFilePath];
[self openExtractedFolderWithZipPath:zipFilePath toDestinationPath:destinationPath];
}
}];
}
Any Suggestions.. Thanks in Advance !
回答1:
Let's just review your code to hopefully help you on your way.
It may seem minor, but pick good variable names:
NSURL *tempDir = [NSURL fileURLWithPath:destinationPath];
NSURL *tmpDirectory = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:tempDir create:YES error:&error];
Two names which are semantically similar for different things, that is just confusing. How about, say, destinationURL
instead of tempDir
?
Next, when constructing/pulling apart/etc. pathnames or URLs you will be better off being consistent. Both NSURL
and NSString
provide similar methods for these operations, in one place you use them:
tmpDirectory = [tmpDirectory URLByAppendingPathComponent:@"extracts"];
but then restort to direct string manipulation using a path separator which may, or may not, be correct:
[destinationPath stringByAppendingString:[NSString stringWithFormat:@"/%@-1",string]]
The routines provided by NSURL
and NSString
abstract away from the details of path separators and how to, say, find the extension on the last path component (which you might find useful when renaming to avoid clashes).
Going back to:
tmpDirectory = [tmpDirectory URLByAppendingPathComponent:@"extracts"];
There is no reason for you to do this. The temporary directory is created for you and you should delete it after using it. So there is no need to create a subdirectory extracts
within it, and by reassigning to the same variable you've lost the URL you need to delete the temporary directory.
Now something less obvious, in my comment above I wrote:
To move each item you must handle name clashes, to do this try the move and if you get an error indicating a name clash modify the destination name however you like and re-try the move, repeating until you succeed or you until reach some limit of tries (determined by you).
I didn't explain why you should do it this way and you have tackled the problem a different way: for each item you are going to move you check for names clashes before attempting the move by iterating over the names in the destination directory.
If you read Apple's documentation on the file system you will find they often recommend you try an operation and then examine any error returned instead of trying to predict whether an error will occur and avoid it. The reason for this is the file system is dynamic, other processes can be modifying it, so if you try to avoid an error you may still get one. In pseudocode you are better of doing something like:
moveDone = false
attemptCount = 0
while not moveDone and attemptCount < MAX_ATTEMPTS
move object
if object exists error
modify destination URL
increment attemptCount
else
moveDone = true
end
end
if not moveDone then handle error
Following this outline and using a simple count and the NSString
/NSURL
path routines will produce you a much simpler and more reliable solution than the one you have now posted as an answer.
HTH
回答2:
Here is the code working for me.
NSURL *tempDir = [NSURL fileURLWithPath:destinationPath];
NSError *error;
NSURL *tmpDirectory = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:tempDir create:YES error:&error];
if (error) {
return ;
}
tmpDirectory = [tmpDirectory URLByAppendingPathComponent:@"extracts"];
NSLog(@"temp dir %@",tmpDirectory);
NSLog(@"temp path %@",tmpDirectory.path);
[SSZipArchive unzipFileAtPath:zipFilePath toDestination:tmpDirectory.path];
NSArray *dirFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectory.path error:nil];
NSLog(@"dir file %@",dirFiles);
for (NSString *string in dirFiles) {
NSArray *dirDestinationFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:destinationPath error:nil];
NSLog(@"dir destination file %@",dirDestinationFiles);
NSMutableArray *folderCount = [[NSMutableArray alloc] init];
NSMutableArray *folderNumCount = [[NSMutableArray alloc] init];
[dirDestinationFiles enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj containsString:string]){
[folderNumCount addObject:obj];
}
if ([string isEqualToString:obj]) {
[folderCount addObject:string];
}
}];
NSFileManager *fm = [NSFileManager defaultManager];
NSError *error;
if (folderCount.count == 0) {
NSLog(@"First time extract");
BOOL isMoved = [fm moveItemAtPath:tmpDirectory.path toPath:[destinationPath stringByAppendingString:[NSString stringWithFormat:@"/%@",string]] error:&error];
if (isMoved) {
NSLog(@"Moved");
}else{
NSLog(@"errorL %@", error);
NSLog(@"Not moved");
}
[fm removeItemAtPath:tmpDirectory.path error:&error];
// [self moveFileToTrash:zipFilePath];
// [self openExtractedFolderWithZipPath:zipFilePath toDestinationPath:destinationPath];
}else if (folderCount.count > 0){
NSLog(@"Already present");
BOOL isMoved = [fm moveItemAtPath:tmpDirectory.path toPath:[destinationPath stringByAppendingString:[NSString stringWithFormat:@"/%@-%lu",string,folderNumCount.count-1]] error:&error];
if (isMoved) {
NSLog(@"Moved");
}else{
NSLog(@"errorL %@", error);
NSLog(@"Not moved");
}
[fm removeItemAtPath:tmpDirectory.path error:&error];
// [self moveFileToTrash:zipFilePath];
// [self openExtractedFolderWithZipPath:zipFilePath toDestinationPath:destinationPath];
}
}
来源:https://stackoverflow.com/questions/51614004/unable-to-rename-the-file-while-moving-from-temporary-directorary