I'm using a bit of code that a user posted here modified for my settings to do a file copy with a progress bar (from Cocoa is my Girlfriend http://www.cimgf.com/2008/05/03/cocoa-tutorial-file-copy-with-progress-indicator/ ).
I have attempted to fix some of the use of deprecated methods and in the process have broken detecting file size. I spent most of the day yesterday trying different things to fix it but haven't had any luck. I should also note that sourceFilePath is obtained from a NSTextField.
I know the error message says the file doesn't exist but it certainly does. It's path doesn't contain any sym links and to be sure I used the NSString method stringByResolvingSymlinksInPath. Any ideas what's going wrong here? Here's the code, and the error message I get.
- (IBAction)startCopy:(id)sender;
{
NSError *attributeserror = nil;
NSString *accountsourcestring = [sourceFilePath stringValue];
NSString *accountsourcestringpath =[accountsourcestring stringByStandardizingPath];
// Use the NSFileManager to obtain the size of our source file in bytes.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary *sourceAttributes = [fileManager attributesOfItemAtPath:accountsourcestringpath error:&attributeserror];
NSNumber *sourceFileSize= [sourceAttributes objectForKey:NSFileSize];
long long fileSize = [sourceFileSize longLongValue];
NSLog(#"Filesize = %lld", fileSize);
NSLog(#"sourcefilepath: %#", accountsourcestring);
if ((sourceFileSize = [sourceAttributes objectForKey:NSFileSize]) )
{
// Set the max value to our source file size
[progressIndicator setMaxValue:(double)[sourceFileSize unsignedLongLongValue]];
}
else
{
// Couldn't get the file size so we need to bail.
NSLog(#"Unable to obtain size of file being copied. Error %# Source file size: %#, sourceAttributes: %#", attributeserror, sourceFileSize, sourceAttributes);
return;
}
And here's the error message logged in console:
2012-09-01 11:23:07.061 Copy File[1004:303] Filesize = 0
2012-09-01 11:23:07.062 Copy File[1004:303] sourcefilepath: file://localhost/Users/daniel/Lion%20plists/
2012-09-01 11:23:07.072 Copy File[1004:303] Unable to obtain size of file being copied. Error Error Domain=NSCocoaErrorDomain Code=260 "The file “Lion%20plists” couldn’t be opened because there is no such file." UserInfo=0x100173770 {NSFilePath=file:/localhost/Users/daniel/Lion%20plists, NSUnderlyingError=0x100140240 "The operation couldn’t be completed. No such file or directory"} Source file size: (null), sourceAttributes: (null)
Related
Here I want to achieve a function which can copy a res file from main bundle (which is added manually from Mac Finder to Xcode project ) (Fig 1) to Document Folder.
Click here to see the Xcode project structure
And to achieve that goal, I use NSFileManager. Here is the function code:
- (void)addCamConfig {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *destPath = [documentsDirectory stringByAppendingPathComponent:CAM_CONFIG];
if (![fileManager fileExistsAtPath:destPath]) {
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"cam" ofType:#"yaml"];
BOOL ret = [fileManager copyItemAtPath:sourcePath toPath:destPath error:&error];
if (error) {
NSLog(#"cam_ret:%d\nsourcePath:%#\ndestPath:%#\nerror:%#",ret,sourcePath,destPath,error.description);
}
}
}
In that case, sourcePath and destPath are both ensured not to be nil.
But strange thing happened in the first time, "copyItemAtPath:sourcePath toPath:destPath error:&error" return "NO" and error log showed below:
cam_ret:0
sourcePath:/private/var/containers/Bundle/Application/3DF49723-E11D-4D67-AD0F-39C2B82B80A4/NitroDemo.app/cam.yaml
destPath:/var/mobile/Containers/Data/Application/181F8B72-402B-4D0C-91D5-0D9759BC607E/Documents/nitro/cam.yaml
error:Error Domain=NSCocoaErrorDomain Code=4 "The file “cam.yaml” doesn’t exist." UserInfo={NSSourceFilePathErrorKey=/private/var/containers/Bundle/Application/3DF49723-E11D-4D67-AD0F-39C2B82B80A4/NitroDemo.app/cam.yaml, NSUserStringVariant=(
), NSDestinationFilePath=/var/mobile/Containers/Data/Application/181F8B72-402B-4D0C-91D5-0D9759BC607E/Documents/nitro/cam.yaml, NSFilePath=/private/var/containers/Bundle/Application/3DF49723-E11D-4D67-AD0F-39C2B82B80A4/NitroDemo.app/cam.yaml, NSUnderlyingError=0x2826476f0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}
Surprisingly, when I run project second time, the error disappeared, "copyItemAtPath:sourcePath toPath:destPath error:&error" return "YES".
And if I remove this app from my iPhone, then rebuild the project , reinstall and run the app first time, the same error message appears again. And as I expected, when I run the project second time, the error disappeared.
So I wonder what exactly happened in the first time and second time?
====================
UPDATE: I solved this problem by creating an intermediate folder nitro.
The key point here is that, as you may not noticed in the log, the dest path XXX/Documents/nitro/cam.yaml contains a not existed intermediate folder nitro. So in the first time when I call copyItemAtPath:sourcePath toPath:destPath error:&error, it fails and may create that folder (just for my guess). As a result, when I run second time, the copyItemAtPath:sourcePath toPath:destPath error:&error returns YES.
Ok, based on the update you could solve it then by inserting something like below.
[NSFileManager.defaultManager createDirectoryAtPath:newDir
withIntermediateDirectories:YES
attributes:nil
error:NULL];
I know that the iOS Simulator is found in a different directory each time it is run; with that in mind, I have this code which gives me the directory of the Core Data sqlite files:
// find current directory for saori.sqlite
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentDirectory = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]firstObject];
NSString *sqliteFilePath = [[documentDirectory URLByAppendingPathComponent:#"Application Support/SalonBook/saori.sqlite"] absoluteString];
if ([fileManager fileExistsAtPath:sqliteFilePath])
[MagicalRecord cleanUp]; // set stack, etc to 'nil'
else {
NSLog(#"\n\n-->sqlite files not found"); // log message "unable to find sqlite files
return;
}
This is the printout of the sqliteFilePath object:
Printing description of sqliteFilePath:
file:///Users/rolfmarsh/Library/Developer/CoreSimulator/Devices/1EE69744-255A-45CD-88F1-63FEAD117B32/data/Containers/Data/Application/C8FF20F0-41E4-4F26-AB06-1F29936C2208/Library/Application%20Support/SalonBook/saori.sqlite
And this is the image of the file from Finder:
The problem is: I go to the sqliteFilePath and the saori.sqlite file is indeed there! Why is -fileExistsAtPath failing?
Because it is still a URL. A file path doesn't have a protocol, so the prefix of your path file:/// is invalid and can't be resolved. Since an invalid path doesn't contain any files, fileExistsAtPath: returns NO.
Not to worry though, instead of calling absoluteString on the URL object, you can just call path instead and it will return the path.
Im trying to move files. Below I'm testing if the paths exist. They do, however both copyItemAtPath and moveItemAtPath don't seem to work.
NSString *testUrl = #"/Users/justinshulman/Documents/test2";
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl]) {
NSLog(#"yes");
}
NSString *testUrl2 = #"/Users/justinshulman/Documents/test1";
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl2]) {
NSLog(#"yes");
}
NSLog(#"%#",testUrl);
NSLog(#"%#",testUrl2);
[[NSFileManager defaultManager]copyItemAtPath:testUrl2 toPath:testUrl error:nil];
[[NSFileManager defaultManager]moveItemAtPath:testUrl2 toPath:testUrl error:nil];
That is exactly your problem, both move and copy will not actually overwrite the destination file if it already exists. You'll have to remove it first and then copy (or move) the other file to that URL.
Try with
[[NSFileManager defaultManager] removeItemAtPath:testUrl error:nil];
[[NSFileManager defaultManager]copyItemAtPath:testUrl2 toPath:testUrl error:nil];
and it should work fine.
You should also be checking for the error instead of passing nil.
NSError* error = nil;
[[NSFileManager defaultManager]copyItemAtPath:testUrl2 toPath:testUrl error:&error];
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
It also returns a bool on whether the copy was successful.
Adding to #micantox answer, always read the class reference. See class reference for NSFileManager:
If a file with the same name already exists at dstPath, this method
aborts the copy attempt and returns an appropriate error.
You should pass NSError object in error filed.
[[NSFileManager defaultManager]copyItemAtPath:testUrl2 toPath:testUrl error:&error];
Error Domain=NSPOSIXErrorDomain Code=17 UserInfo=0x100457e80 "The operation couldn’t be completed.
[[NSFileManager defaultManager]moveItemAtPath:testUrl2 toPath:testUrl error:&error];
Error Domain=NSCocoaErrorDomain Code=512 UserInfo=0x1004a2270
Use replaceItemAtURL:withItemAtURL:backupItemName:options:resultingItemURL:error:
Replaces the contents specified by the first URL with the contents of
the second URL in a manner that insures no data loss occurs.
#justin, First thing it never works only. Because you are trying to copy the source path to destination path where both path are same. Second thing, how NSFileManager copy or move api works is, you have to copy or move source path to different destination path with appending your appropriate path component. For example see the code below:--
NSString *testUrl = #"/Users/home/Documents/source.rtf";
//
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl]) {
NSLog(#"yes");
}
//Below destination is folder name which should be exist on your machine or else you can create programmatically as well
NSString *testUrl2 = #"/Users/home/Documents/destination";
NSLog(#"%#",testUrl);
NSLog(#"%#",testUrl2);
NSError *err=nil;
//Now we are copying the souce path to destination folder with appending file name (it can be any your name becuase file manager copy source file contents to your destination file contents)
//Here given file name is a destination.rtf where you can give any your name. Also this is for copying source contents to destination contents
NSFileManager *fm=[NSFileManager defaultManager];
if ([fm copyItemAtPath:testUrl toPath:[testUrl2 stringByAppendingPathComponent:#"destination.rtf"] error:&err])
{
NSLog(#"success");
}
else
{
NSLog(#"%#",[err localizedDescription]);
}
I am trying to copy a file using [[NSFileManager defaultManager] copyItemAtPath: toPath: error:] but it is failing with the following error:
4: The file does not exist.
The relevant code is below, and the file does exist and the path string is correct because it is created beforehand with the exact same file path string.
NSFileManager* manager = [NSFileManager defaultManager];
NSError* error;
NSString* fileName = [Sound getFileName:Title];
NSString* oldDirectory = [NSString stringWithFormat:#"%#%#/", [settings stringForKey:#"downloadFolder"], authorFolder];
NSString* oldFile = [oldDirectory stringByAppendingFormat:#"%#.mp3", fileName];
NSString* newFile = [NSString stringWithFormat:#"%#/iTunes/iTunes Media/Automatically Add to iTunes/%#.mp3", [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) objectAtIndex:0], fileName];
BOOL result = [manager copyItemAtPath:oldFile toPath:newFile error:&error];
if (!result && error)
{
NSLog(oldFile);
NSLog(#"There was an error copying the file to the iTunes directory! %#", [error localizedDescription]);
}
It's not the exact code, but all relevant code should be above. If I use [manager fileExistsAtPath:oldFile] the result is YES.
What could cause the copy to fail and say the file doesn't exist, even if it does?
UPDATE:
Issue fixed. Turns out the output folder was really Automatically Add to iTunes.localized, but I didn't notice this initially when just paging through the finder. Fixing the output path solved the issue! Thanks for the help.
If any of the directories in the path of the destination don't exist, you'll get a similar error to what you'd get if the source doesn't exist. Check what [manager fileExistsAtPath:[newFile stringByDeletingLastPathComponent] isDirectory:&isDir] returns.
You're using the API wrong. You need to look at the return value of -copyItemAtPath:toPath:error:. Only if that returns NO does that mean an error occurred.
If you're using ARC, your error variable should be nil if no error occurred (although this isn't technically guaranteed), but if you're using MRR it probably won't, because you never initialized it.
I've got a small utility application that parses a csv-file and uses the data to fill a Core Data store for use with another application. I open the csv-file using -initWithContentsOfFile:encoding:error: and the method always returns nil with the error
Error Domain=NSCocoaErrorDomain Code=260 UserInfo=0x100106450 "The file “data.csv” couldn’t be
opened because there is no such file." Underlying Error=(Error Domain=NSPOSIXErrorDomain Code=2 "The
operation couldn’t be completed. No such file or directory"), {
NSFilePath = "/Users/****/Library/Developer/Xcode/DerivedData/CreateData-
bhkmspyczgcfcrgehcbaydwdbfoa/Build/Products/Debug/data.csv";
NSUnderlyingError = "Error Domain=NSPOSIXErrorDomain Code=2 \"The operation couldn\U2019t be
completed. No such file or directory\"";
}
Now, I'm looking at that exact file in that exact directory. Even more confusing is the fact that I have another version of essentially the same utility for another app that works -- the only difference is the makeup of the core data store and entities and the number of columns in the csv file, all of which are invoked after loading the csv file. Or failing to load, as it were ...
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
NSString *csvFile = [[NSString alloc] initWithContentsOfFile:csvFilePath(QUESTIONS_INPUT_FILENAME) encoding:NSASCIIStringEncoding error:&error]; // This fails
if (error != nil) {
NSLog(#"Returned error:\n%#, %#", error, [error userInfo]); // Returns the above error message
exit(1);
}
// ...
}
NSString *csvFilePath(NSString *inputFileName) {
NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
return [resourcePath stringByAppendingPathComponent:inputFileName];
}
NSString *applicationDocumentsDirectory() {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
It fails because you aren't passing in the actual location of the file, just the filename, so it is trying to look for it in the program's own folder - you're using the path of the bundle. unless that's where your csv file is, it won't find it.
To put it simply the file path you passed is incorrect thus can't be found or does not exist.