NSFileManager rename file using "moveItemAtURL:" with a name contains path separator like "foo/bar.extension" - macos

This feels weird, my code goes as simple as
// something like "foo/bar"
NSString *correctFileName = seriesDict[seriesNumber];
if (correctFileName.length > 0)
{
// So I'll have a fileName like "foo/bar.extension" which looks like a directory and a file in it...
NSString *pathExtension = [filePath pathExtension];
NSString *correctFilePath = [[[filePath stringByDeletingLastPathComponent]
stringByAppendingPathComponent:correctFileName]
stringByAppendingPathExtension:pathExtension];
NSError *error = nil;
[[NSFileManager defaultManager] moveItemAtPath:filePath toPath:correctFilePath error:&error];
// And NSFileManager can not treat it as a legal fileName, kind of expected...
if (error)
{
NSLog(#"Rename file at %# failed, error: %#", filePath, error);
}
}
Seems it's ok to rename my file to "foo/bar.extension" in Finder, like this
there might be a solution to do that in code.
If anybody could shred in some light, it'll be highly appreciated.

The / in Finder is converted to a :. / is invalid in POSIX-style paths, while : is invalid in HFS-style paths, so macOS maps those two characters to each other.
The technically correct way would be to create a CFURL using CFURLCreateWithFileSystemPathRelativeToBase specifying kCFURLHFSPathStyle as the path style, and resolving against a base URL you've already created. You'd then copy the path of the full URL using CFURLCopyFileSystemPath.
Pragmatically speaking though, you can simply do a string replace between / and :.

Related

get file attributes with nsfilesustem in cocoa no such file exists

I've searching for about 3 hours of how to get the creation date of a file, I get the URL with an enumerator, after that I pass it to path correcting the percents, and finally I try to get the file attributes...so, I don no alter the path in anyway but I always get the same error "The operation couldn’t be completed. No such file or directory", and the path "file:///Users/raul/Desktop/DSC_0386.JPG".
The code sample:
NSError* error = nil;
//NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:[[url absoluteString] stringByRemovingPercentEncoding] error:&error];
NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:#"file://Users/raul/Desktop/DSC_0386.JPG" error:&error];
NSLog(#"%#",error);
NSDate *fecha = [fileAttribs objectForKey:NSFileCreationDate];
I've commented the first NSDictionary to try out the second statement with the nsstring directly.
I've checked that my file already exists.
Please, any help?? I'm missing anything?
Several issues:
1) In most cases, you shouldn't have to convert an NSURL to a path string in order to operate on a file. In particular, you can use the "resource value" API of NSURL to get the creation time directly:
NSDate* creationDate;
NSError* error;
if ([url getResourceValue:&creationDate forKey:NSURLCreationDateKey error:&error])
/* use creationDate */;
else
/* handle error */;
2) If you do need to get a path string from NSURL, don't use -absoluteString. That will still be a URL string, with things like "file://", etc. A URL string is not a valid path string. The error message you quoted in your question was already telling you this. It showed you a file "path" of "file:///Users/raul/Desktop/DSC_0386.JPG", but that's not a path at all.
You should just use the -path method. You do not need to do anything with percent encoding when you get the -path.
3) You should ignore any error output parameter until you have checked whether the method you called succeeded or failed, usually by examining its return value. That is, the code you posted should be reorganized like this:
NSError* error = nil;
NSDictionary* fileAttribs = [[NSFileManager defaultManager] attributesOfItemAtPath:#"file://Users/raul/Desktop/DSC_0386.JPG" error:&error];
if (fileAttribs)
{
NSDate *fecha = [fileAttribs objectForKey:NSFileCreationDate];
// ... use fecha ...
}
else
NSLog(#"%#",error);

NSFileManager says a file not writable Mac

I have been trying to use AVFoundation to record screen outputs. For reasons unknown it stopped working after I moved to the latest version of Mac (Mountain Lion). I have been trying to getting it work but is not fruitful so far. I know that the AVFoundation method startRecordingToOutputFileURL will not work if the output file already exists. So, I tried using NSFileManager to see if my destination file exists and if it is writable. My Filemanager always returns the values corresponding to non-existence of the destination file and not writable. I tried to set file permissions to no avail, could anyone throw some light on my possible mistake:
dest = [[NSURL alloc] initFileURLWithPath:#"~/Desktop/myMovie.mov"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSNumber numberWithInt:777] forKey:NSFilePosixPermissions]; //I tried 511 too, no avail
[fileManager setAttributes:attributes ofItemAtPath:[dest path] error:nil];
if (![fileManager fileExistsAtPath:[dest path]]) {
if ([fileManager isWritableFileAtPath:[dest path]]) {
/* Starts recording to a given URL. */
[captureMovieFileOutput startRecordingToOutputFileURL:dest recordingDelegate:self];
}
else{
NSLog(#"File doesnot exist but is not writable"); //This is the message I get as result
}
}
else
{
NSLog(#"File Exists...");
}
Unexpanded tildes are not valid paths in Cocoa. You must use -stringByExpandingTildeInPath or better, -stringByStandardizingPath on the string passed into NSURL's -initFileURLWithPath:.
Because of this, NSFileManager will return NO for isWritableFileAtPath because it's an invalid path (so it's not writable). This leads you to your NSLog() being fired.
Update based on comments:
You may still find NSURL is returning nil upon creation (so calling -path will return nil) because the path is still invalid. Also worth noting, the documentation says for -isWritableFileAtPath:, "It's far better to attempt an operation (such as loading a file or creating a directory), check for errors, and handle those errors gracefully than it is to try to figure out ahead of time whether the operation will succeed."
Take Peter Hosey's suggestion and make use of the NSError if the call fails as you attempt to write to the file and don't try to figure it out ahead of time.

Check if two files are the same in Cocoa

How do you efficiently check if two files are the same (have the same data) in Cocoa?
Context: I'm writing a program that receives a file as input (input file) and copies it into a directory. If the directory already contains a file with the same name (namesake file) then the input file should be copied with a new name only if the namesake file is different.
you can use -[NSFileManager contentsEqualAtPath:andPath:].
From the Docs:
If path1 and path2 are directories, the contents are the list of files and subdirectories each contains—contents of subdirectories are also compared. For files, this method checks to see if they’re the same file, then compares their size, and finally compares their contents. This method does not traverse symbolic links, but compares the links themselves.
While Justin answered my question, I was using NSFileWrapper internally so I couldn't always use contentsEqualAtPath:andPath:.
In case it helps anyone, here's what I wrote to compare the contents of a NSFileWrapper to the contents of a file:
- (BOOL) contentsOfFileWrapper:(NSFileWrapper*)fileWrapper equalContentsAtPath:(NSString*)path {
NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
NSUInteger fileSize = [attrs fileSize];
NSUInteger fileWrapperSize = [fileWrapper.fileAttributes fileSize]; // Will return zero if the file wrapper hasn't been written
if (fileWrapperSize > 0 && fileSize != fileWrapperSize) return NO;
NSData *fileData = [NSData dataWithContentsOfURL:fileURL];
NSData *fileWrapperData = fileWrapper.regularFileContents;
return [fileData isEqualToData:resourceData];
}
As Justin suggested, I'm only using the above method if I'm unable to reconstruct the path of the file wrapper. If I can, then I use contentsEqualAtPath:andPath:.

strange behavior of xcode 4.2

Strange and funny think is going on
Code:
-(void)saveFile
{
NSFileManager *fileMng = [NSFileManager defaultManager];
if(![fileMng fileExistsAtPath:self.appFilesPath])
{
NSError *error = nil;
BOOL success = [fileMng createDirectoryAtPath:self.appFilesPath withIntermediateDirectories:YES attributes:nil error:&error];
if(!success)
{
NSLog([error localizedDescription]);
}
}
NSLog([NSString stringWithFormat:#"%#",self.appFilesPath]);
[fileMng createFileAtPath:self.fileFullPath contents:self.fileData attributes:nil];
[self.fileData writeToFile:self.fileFullPath atomically:YES];
}
and this line
NSLog([NSString stringWithFormat:#"%#",self.appFilesPath]);
should give me something like this
file://localhost/Users/user/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/BF35B859-514B-45AA-8E3A-B2CE65BD82B6/Documents/AppFiles
Directory AppFiles should be created under ../Documents/ directory,
but it's not there...
and the nslog gives me something like this:
file://localhost/Users/user/Library/Application瑳楲杮楗桴潆浲瑡:敲敬獡e摡䕤瑮楲獥牆浯楄瑣潩慮祲:扯敪瑣潆䭲祥:汣獡s獩楋摮晏汃獡㩳氀湥瑧h畡潴敲敬獡e敳佴橢捥㩴潦䭲祥:敲潭敶扏敪瑣潆䭲祥:湩整敧噲污敵戀潯噬污敵爀浥癯䅥汬扏敪瑣s湩瑩猀慨敲䥤獮慴据e敲楧瑳牥敎睴牯䑫晥畡瑬䙳牯灁䥰㩄挀灯y摡佤橢捥㩴洀楡䉮湵汤e畢摮敬摉湥楴楦牥椀䕳畱污潔瑓楲杮:桳牡摥潃普杩牵瑡潩n潣湵牴䑹晥畡瑬潆..few more screens of this bush..帴㽻椽絩8筞㴿楩}ㅶ䀶㨰帴㽻椽絩椸㈱䀀䜢佅楐數偬楯瑮"㽻搽絤䀸㨰4㉶䀴㨰笴㴿摤㡽䀀倢剂煥敵瑳牥"ㅶ䀶㨰⌴匸㈱䀀㰢䕇协灵潰瑲摥楔敬敓獴敓癲牥牐硯䑹汥来瑡㹥"㍶䀶㨰笴㴿摤㡽㉤椴㈳瘀㘱぀㐺㡀ㅩ2㉶䀸㨰帴㽻搽絤䤸㈱ㅤ椶㐲瘀㈱぀㐺癞8ㅀ䀶㨰帴㡶ㅣ2筞硟捰损湯敮瑣潩彮㵳}ㅀ䀶㨰䀴常彻䍟剆湵潌灯紽㈱帀彻䍟剆湵潌灯紽䀸㨰4筞彟䙃畒䱮潯㵰}癞䀸㨰4ㅀ䀲㨰帴㡶瘀〲぀㐺㡀ㅀ䤲㘱䀀㰢华慃档䑥汥来瑡㹥"㉀䀸㨰䀴笸㴿摤ㅽ2㽻搽絤㠲぀㐺㽻搽絤常㉤4㽻∽慬楴畴敤搢氢湯楧畴敤搢}upport/iPhone 貌Š߈imulator/5.0/Applications/CAF90A92-5B85-4FC0-8482-3702C3E98F8D/Documents/AppFiles
when i run code second time, the if condision is skiped, but ../Documents/ directory is stil empty
来瑡㹥"㉀䀸 - i mean wtf, first time something like this,
restarting xcode, mac did't help,
simulator is all set to english,
it also happen in other projects,
keyboard setting ant nationalization looks ok,
so realy I have no clue what is wrong
any ideas?
You can not just NSLog a string. The string argument it takes is a format (like in printf) which interpeted specially. In your case, it is reading random memory because %20S means to interpret the next argument as pointer to null-terminated string of wide characters and print it right-aligned in 20 columns; and they are Chinese because most of Unicode is occupied by Chinese hieroglyphs.
This is the correct way to do it:
NSLog(#"%#", self.appFilesPath);

Declare String then open string from Path with Cocoa

I've Declared a string Like so
NSString* fileName = [files objectAtIndex:i];
NSLog(fileName);
NSImage* imageFromBundle = [[NSImage alloc] initWithContentsOfFile:fileName];
and want to use that filename to open a file in a different directory.
I came up with this
NSImage* imageFromBundle2;
imageFromBundle2 = [[NSImage alloc] initWithContentsOfFile:#"/Users/rhaynes/Documents/works4/" filename ];
Any help would be appreciated
I'll assume that your fileName string is actually a file name, like "myImage.png". A lot of the Objective-C docs refer to a file name when they really mean file path - so sometimes it's confusing.
What you want to do is create an NSString that represents the complete path to the file you want to load. For instance, you could say:
NSString * path = [NSString stringWithFormat: #"/Users/rhaynes/Documents/works4/%#", fileName];
That line creates a new NSString using the format string and parameters provided (the %# in the format string indicates that the string value of fileName should be inserted there.) StringWithFormat is a really powerful function, so you should definitely check it out in the docs.
Then you could call initWithContentsOfFile:path, and it should give you the image you want.
NSString* fileName = [files objectAtIndex:i]; NSLog(fileName);
Don't pass non-hard-coded strings as format-string arguments. If they contain format specifiers, you'll get garbage or a crash. (Try this with fileName = #"foo%sbar", for example. Then try it with fileName = #"foo%fbar" for even more fun.)
Your NSLog statement should be:
NSLog(#"%#", fileName);
[I] want to use that filename to open a file in a different directory. I came up with this
NSImage* imageFromBundle2; imageFromBundle2 = [[NSImage alloc] initWithContentsOfFile:#"/Users/rhaynes/Documents/works4/" filename ];
You can only concatenate string literals this way; as you've no doubt seen for yourself, this is a syntax error when one of the strings isn't a literal.
First off, if fileName is actually a pathname, you'll need to use lastPathComponent to get the actual filename. So:
NSString *path = [files objectAtIndex:i];
NSString *filename = [path lastPathComponent];
Then, use stringByAppendingPathComponent: to tack this onto the new superpath.
NSString *desiredFilenamePath = [directoryPath stringByAppendingPathComponent:filename];
Now you have the pathname you wanted to pass to NSImage's initializer.

Resources