Use NSOpenpanel and NSfilemanager to find contents of directory - objective-c

I'm new to objective-c so please excuse my lack of knowledge. I have a snippet of code here that I can't seem to get working properly. What I'd like to do is present a directory selection panel upon a button click. Once the user selects a directory I'd like to make an array of everything in the directory. Eventually I want to use this array to have a list of sub-directories and files (everything in the directory the user selects) to be copied to another location.
I have a warning that says Instance method '-contentsofdirectoryaturl:options:error' not found (return type defaults to id). I'm not exactly sure what that means or how to fix it and I suspect that this is my problem. Any advice provided would be great. Thanks!
- (IBAction)selectfiles:(id)sender {
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setCanChooseDirectories:YES];
[openPanel setCanChooseFiles:NO];
[openPanel setAllowsMultipleSelection:NO];
if ( [openPanel runModal] == NSOKButton ) {
NSArray *accountPath = [openPanel URLs];
NSLog (#"%#", accountPath);
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSArray *contents;
contents = [filemgr contentsOfDirectoryAtURL:accountPath options:(NSDirectoryEnumerationSkipsHiddenFiles) error:nil];
}
}

contentsOfDirectoryAtURL: has an additional argument includingPropertiesForKeys: which you have omitted. That is why the compiler warns you. That argument is a list of properties you want to be prefetched. In the simplest case, you can specify an empty array.
Another error is that [openPanel URLs] returns an array of URLs, even if only one item is selected.
So your code should look like this:
NSURL *accountPath = [[openPanel URLs] objectAtIndex:0];
NSLog (#"%#", accountPath);
NSFileManager *filemgr;
filemgr = [NSFileManager defaultManager];
NSArray *contents;
contents = [filemgr contentsOfDirectoryAtURL:accountPath
includingPropertiesForKeys:[NSArray array]
options:(NSDirectoryEnumerationSkipsHiddenFiles)
error:nil];

Related

How to fill the URLs array of the NSOpenPanel with absolute file path?

I am trying to create a panel that lets the user choose a path to save a file. When the user selects a directory from the panel that shows relative path (i.e. /folder) the URLs property is contains /folder. When the user selects a directory that shows the full path, URLs property of panel contains the full path (i.e. /User/name/folder). How do I ensure the URLs property will definitely contain the full paths even though the user's panel shows a relative path?
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];
[panel setAllowsMultipleSelection:NO]; // yes if more than one dir is allowed
NSInteger clicked = [panel runModal];
NSArray<NSURL *> *URLs;
if (clicked == NSFileHandlingPanelOKButton) {
URLs = [panel URLs];
}
else{
URLs = [NSArray arrayWithObject:[NSURL URLWithString:[NSString stringWithFormat:#"file://%s/", getenv("HOME")]]];
}
for (NSURL *url in URLs) { // When user clicks cancel, [panel URLs] is empty
NSString *selectedDirectoryPath = [url.absoluteString substringFromIndex:6];
// NSString *selectedDirectoryPath = [url path];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *sourceFilePath = [NSString stringWithFormat:#"%#/%#", NSHomeDirectory(), _fileName];
NSString *destFilePath = [NSString stringWithFormat:#"%#%#", selectedDirectoryPath, _fileName];
}
I thought I could use the path instance property on url, but the array is filled once the user clicks OK to a file path with NSFileHandlingPanelOKButton.
Edit: I found a response that suggests to use beginSheetModalForWindow in NSOpenPanel URL to string , but how do you use this function?
I used setDirectoryURL to open the panel to the root folder by default. This will help ensure it returns an absolute path, otherwise a relative path is returned.
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setDirectoryURL:[NSURL URLWithString:[NSString stringWithFormat:#"file:///"]]];

Security-Scoped Bookmarks for a directory

I need to give full read/write permission for a directory where the application write some file to this directory. I read that using sandboxed application it required to Enable Security-Scoped Bookmark and URL Access to access a folder after relaunch the app.
So I am trying to implement it based on the code here with some minor modification What is the correct way to handle stale NSURL bookmarks?
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseDirectories:YES];
[openDlg setCanCreateDirectories:YES];
[openDlg setAllowsMultipleSelection:FALSE];
if ( [openDlg runModal] == NSOKButton )
{
NSArray *files = [openDlg URLs];
NSString* dirPath =[[files objectAtIndex:0] path];// absoluteString];
BOOL isDirectory;
NSFileManager* manager = [NSFileManager defaultManager];
NSString *Dir = [dirPath stringByAppendingPathComponent:#"ScreenCaptures"];
if (![manager fileExistsAtPath:Dir isDirectory:&isDirectory] || !isDirectory)
{
NSError *error = nil;
[manager createDirectoryAtPath:Dir
withIntermediateDirectories:NO
attributes:nil
error:&error];
if (error)
NSLog(#"Error creating directory snap path: %#", [error localizedDescription]);
}
NSURL *url = [NSURL URLWithString:[Dir stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *bookmark = nil;
NSError *error = nil;
bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil // Make it app-scoped
error:&error];
if (error) {
NSLog(#"Error creating bookmark for URL (%#): %#", url, error);
[NSApp presentError:error];
}
NSLog(#"bookmark: %#", bookmark);
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:bookmark forKey:#"bookmark"];
}
But the above code giving me the error
016-08-20 02:19:53.390 FileAccess[635:85753] modalSession has been exited prematurely - check for a reentrant call to endModalSession:
2016-08-20 02:19:59.979 FileAccess[635:85753] Error creating bookmark for URL (/Users/development/Documents/c/ScreenCaptures): Error Domain=NSCocoaErrorDomain Code=262 "Scoped bookmarks can only be made with file URLs" UserInfo={NSURL=/Users/development/Documents/c/ScreenCaptures, NSDebugDescription=Scoped bookmarks can only be made with file URLs}
2016-08-20 02:20:00.021 FileAccess[635:85753] CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
2016-08-20 02:20:04.967 FileAccess[635:85753] bookmark: (null)
What could be the problem?, anything wrong on above code.
Your second error message tells you what is wrong - you haven't used a file:// URL.
This can be fixed by creating the URL properly from your path variable, however you will probably be better of sticking with URLs throughout and not doing the URL -> path -> URL transformation. All the operations you've used the path for can be done directly with URLs, just check the documentation for NSFileManager and NSURL. The only one which may be non-obvious is using NSURL's checkResourceIsReachableAndReturnError: rather than NSFileManager's fileExistsAtPath:, however read the documentation for checkResourceIsReachableAndReturnError: carefully and take its advice.
Making these changes should address at least three of the errors you have reported.
HTH

Get file type description by extension

How can I get the description of the file type like it does in Finder.app by using only file extension? In other words I want to get that field in NSString:
Here's a little something quick 'n' dirty that illustrates what you need:
NSOpenPanel *openPanel = [[NSOpenPanel alloc] init];
[openPanel runModal];
NSString *path = [[openPanel URL] path];
NSString *type = [[NSWorkspace sharedWorkspace] typeOfFile:path error:NULL];
NSLog(#"%#", [[NSWorkspace sharedWorkspace] localizedDescriptionForType:type]);
The open panel lets you choose a file. NSWorkspace provides for first determining the UTI of the file (given its path), and then using the UTI to get the localized string describing the file type.
EDIT:
If you positively have got to use only the file extension, then use these three lines instead of the last three above:
NSString *extension = [[[openPanel URL] path] pathExtension];
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef) extension, NULL);
NSLog(#"%#", [[NSWorkspace sharedWorkspace] localizedDescriptionForType:(__bridge NSString *) uti]);
You should get that by supplying the files universal type identifier to localizedDescriptionForType: of NSWorkspace.

How to access Media section (Photo & Movies) directly from NSOpenPanel in Mac OS X application?

I already refered this link
iMedia
Now i am using NSOpenPanel to open iPhoto library folder.
Here is the code which allow to open.
int i = 0;
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
[openDlg setCanChooseFiles:YES];
[openDlg setAllowedFileTypes:[NSArray arrayWithObjects:#"public.image",#"public.video",nil]];
[openDlg setAllowsMultipleSelection:TRUE];
[openDlg setAllowsOtherFileTypes:NO];
if ( [openDlg runModal] == NSOKButton )
{
NSArray *files = [openDlg URLs];
for( i = 0; i < [files count]; i++ )
{
NSLog(#"File path: %#", [[files objectAtIndex:i] path]);
}
}
This code always open my Finder library folder, As i want to open Media Photo and Movies folder directly.
Please give me any solution.
I have attached here one screen shot.
Thanks & Regards,
You may consider adding the following code snipet:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
NSURL *picturesURL = [fileManager URLForDirectory:NSPicturesDirectory inDomain:NSUserDomainMask appropriateForURL:NULL create:NO error:&error];
NSURL *iPhotoURL = [picturesURL URLByAppendingPathComponent:#"iPhoto Library.photolibrary"];
[openDlg setDirectoryURL:iPhotoURL];
// Now run the dialog
This won't help if the user has moved his iPhoto library to some non-standard location.
There is a private API of Apple that contains exactly the control you want to access;
this control is an ILMediaBrowserView and provides the exact same view than the one in NSOpenDialog. If you are planning an AppStore release of your app don't use it but it can be useful. The framework to integrate to your project to get that view is iLifeMediaBrowser.framework in /System/Library/PrivateFrameworks.

Problem getting files from folder, error recognizing folder. (Objective c)

I have the user select a folder from an NSOpenPanel. This returns a filepath like: file://localhost/Folder. Here is my code where it all goes wrong:
NSURL *filePath = [openDlg URL]; //OpenDlg is my NSOpenPanel
NSString *s = [filePath absoluteString];
NSLog(#"%#",s);
NSError *error;
NSArray *b = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:s error:&error];
if (error) {
NSLog(#"%#",error);
}
NSLog(#"%lu",b.count);
Here, no matter what folder I select, this error message is sent: The folder “Folder” doesn’t exist." UserInfo=0x10518b320 {NSFilePath=file://localhost/Folder, NSUserStringVariant=(
Folder
), NSUnderlyingError=0x10515d5e0 "The operation couldn’t be completed. (OSStatus error -43.)"}
What is going on?!? If this isn't the best way to do it how can I access all the files inside of a folder?
Try using this method instead:
- (NSArray *)contentsOfDirectoryAtURL:(NSURL *)url includingPropertiesForKeys:(NSArray *)keys options:(NSDirectoryEnumerationOptions)mask error:(NSError **)error
You can just pass in the NSURL without having to convert it into a NSString. To give you an example of how you would use it, see below:
[[NSFileManager defaultManager] contentsOfDirectoryAtURL:filePathURL
includingPropertiesForKeys:[NSArray arrayWithObjects:NSURLNameKey, nil]
options:NSDirectoryEnumerationSkipsHiddenFiles
error:&error];
I can't see how you setup your NSOpenPanel so I will also include an example of how to set that up below:
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result){
if (result == NSFileHandlingPanelOKButton) {
NSArray* urls = [openPanel URLs];
NSURL *url = [urls objectAtIndex:0];
if (url != nil) {
// If you want to convert the path to a NSString
self.filePathString = [url path];
// If you want to keep the path as a NSURL
self.filePathURL = url;
}
}
}];
The above method will get the path to the file or folder after the user has pressed the OK button. Give that a try and see if it works. To further elaborate on why I suggested you use NSURL, here is the explanation that the Apple Documentation gives:
The preferred way to specify the location of a file or directory is to use the NSURL class. Although the NSString class has many methods related to path creation, URLs offer a more robust way to locate files and directories. For applications that also work with network resources, URLs also mean that you can use one type of object to manage items located on a local file system or on a network server.