Show folder's contents in finder using Swift - swift

I want to be able to select a folder and show its contents in the Finder. I have managed to select the folder itself and select a file within the folder. But I don't know how to show the contents of an empty folder.
e.g.
Folder A/Folder B
I want to display the contents of folder Folder B (which could be empty).
I have written the following code:
func showFolder(fileName : String)
{
var dataPath = homeDirectory.stringByAppendingPathComponent(fileName)
var urlPath = NSURL(fileURLWithPath: dataPath)
var selectedURLs = [urlPath!]
NSWorkspace.sharedWorkspace().activateFileViewerSelectingURLs(selectedURLs)
}
This only opens Folder A with Folder B highlighted. This is very close, but not quite right.
I need to be able to open Folder B with nothing highlighted. I'm obviously using the wrong command.

Use the selectFile method and pass nil as first argument and the path to the folder to be shown as second argument.
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: "/Users/")

2021 | SWIFT 5.1:
func showInFinder(url: URL?) {
guard let url = url else { return }
if url.isDirectory {
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: url.path)
} else {
NSWorkspace.shared.activateFileViewerSelecting([url])
}
}
extension URL {
var isDirectory: Bool {
return (try? resourceValues(forKeys: [.isDirectoryKey]))?.isDirectory == true
}
}
showInFinder:
Folder's url = will show content of the folder.
File's url = will open in Finder file's parent and select file there.
Url is nil = Will do nothing
File/path does not exist = Will do nothing

Swift 2.1 code to Launch OS X Finder
Use the selectFile or activateFileViewerSelectingURLs to select files.
Select 1 item in finder with path YOUR_PATH_STRING
NSWorkspace.sharedWorkspace().selectFile(YOUR_PATH_STRING, inFileViewerRootedAtPath: "")
The second param use empty string, if you specify an empty string "" for this parameter, the file is selected in the main viewer.
If you want to select 1 or more files use activateFileViewerSelectingURLs(_ fileURLs: [NSURL])
To select one file
NSWorkspace.sharedWorkspace().activateFileViewerSelectingURLs([NSURL].init(arrayLiteral: NSURL.init(fileURLWithPath: YOUR_PATH_STRING)))
To select multiple files
let urls : [NSURL] = [NSURL.init(fileURLWithPath: "/Users/USER_NAME/Pictures"),
NSURL.init(fileURLWithPath: "/Users/USER_NAME/Music")]
If you provide item that are not in the same folder more windows selecting the specified files are open.
let urls : [NSURL] = [NSURL.init(fileURLWithPath: "/Users/USER_NAME/Pictures"),
NSURL.init(fileURLWithPath: "/Users/USER_NAME/Music"),
NSURL.init(fileURLWithPath: "/Users")]

Related

How can I iterate inside each directory in resource path

I have a simple scenario, there is a folder called content that contains image file, I want all the image file starting with nssl to be saved to an array , so I do below code, but I cannot seem to think or know a way to find out how I can move in each directory and search for such a file and append to my array , here is my code below , I can get the names of all the directories, but what to do next ?
let path = Bundle.main.resourcePath!
let fm = FileManager.default
do {
let items = try fm.contentsOfDirectory(atPath: path)
for item in items {
}
} catch {
}
FileManager is not needed.
Bundle provides urls(forResourcesWithExtension: subdirectory:) which returns multiple urls for a specific extension
if let urls = Bundle.main.urls(forResourcesWithExtension: "png", subdirectory: "content") {
for url in urls where url.lastPathComponent.hasPrefix("nssl") {
}
}
Change the png extension to the desired type.

Auto create directory when writing a file to a directory that does not exist

I am using File Manager to write files to the users documents directory. Every file is downloaded to a users device via a URL and then I create a local URL by doing the following:
extension URL {
func getLocalUrl() -> URL {
let directoryURL = FileManager.default.getDocumentsDirectory()
let filePath = pathComponents.dropFirst().joined(separator: "-")
return directoryURL.appendingPathComponent(filePath)
}
}
This works perfectly fine. However, when I try to create a local URL by using slashes instead of dashes via the following:
extension URL {
func getLocalUrl() -> URL {
let directoryURL = FileManager.default.getDocumentsDirectory()
let filePath = pathComponents.dropFirst().joined(separator: "/")
return directoryURL.appendingPathComponent(filePath)
}
}
I get the following error when this code runs:
func save(url: URL, fileUrl: URL) {
do {
// fileUrl is a url in the temporary directory from a URLSession.downloadTask
try FileManager.default.moveItem(at: fileUrl, to: url.getLocalUrl())
} catch {
print("download.service.write.error: \(error)")
}
}
CFNetworkDownload_sKaBto.tmp” couldn’t be moved to “user-data” because either the former doesn’t exist, or the folder containing the latter doesn’t exist."
As you can see the error is because I am trying to write to a directory that does not exist. Is there a way to auto create the directory if it does not exist?

macOS - How to have NSSavePanel to add a file extension in the file name?

I'm using this code to give the user the choice to specify a name and a location where to save a plain text file on disk. All seems to work but the saved file hasn't any extension. Actually I have not specify an extension in any part of my code, I read NSSavePanel documentation without notice the part where explained this option.
Here is the code I'm using:
let textToExport = mainTextField.textStorage?.string
if textToExport != "" {
let mySave = NSSavePanel()
mySave.begin { (result) -> Void in
if result == NSFileHandlingPanelOKButton {
let filename = mySave.url
do {
try textToExport?.write(to: filename!, atomically: true, encoding: String.Encoding.utf8)
} catch {
// failed to write file (bad permissions, bad filename etc.)
}
} else {
NSBeep()
}
}
}
Add the line
mySave.allowedFileTypes = ["txt"]
before presenting the panel.
From the documentation:
The value of this property specifies the file types the user can save
the file as. A file type can be a common file extension, or a UTI. The
default value of this property is nil, which indicates that any file
type can be used. (Note that if the array is not nil and the array
contains no items, an exception is raised.)
If no extension is given by the user, the first item in the
allowedFileTypes array will be used as the extension for the save
panel. If the user specifies a type not in the array, and
allowsOtherFileTypes is true, they will be presented with another
dialog when prompted to save.

Get path of a file in a data set located in Assets.xcassets

I have a data set of audio files in my Assets.xcassets:
I'm trying to get the path of one of those audio files like this:
let path: String = Bundle.main.path(forResource: "acoustic_grand_piano/A4", ofType: "f32")!
But I get a EXC_BAD_INSTRUCTION. I tried to look on the internet but I don't find anything on Data Sets.
How can I get the content of one of these files?
Thanks!
Try this:
Manually put your files into a folder, named anything you want.
Append ".bundle" to the folder to create a bundle. You'll get a warning, accept it. Congrats, you've just created your first bundle! :-)
Manually drag that folder into your app.
Get at your files by using the following code....
public func returnFile(_ named:String) -> String {
let path: String = Bundle.main.path(forResource: "myAudioFiles", ofType: "bundle")! + "/" + name + ".f32"
do {
return try String(contentsOfFile: path)
}
catch let error as NSError {
return error.description
}
}
Now, my files are text files of CIKernel code. Since your's are audio files you may need to change the String return to something else.
EDIT:
In my case I'm using a framework, as I wish to share these files/images with extensions and other apps. If you are working in such a set up, here's the unaltered code:
public func returnFile(_ resource:String, _ fileName:String, _ fileType:String) -> String {
let identifier = "com.companyname.appname" // replace with framework bundle identifier
let fileBundle = Bundle.init(identifier: identifier)
let filePath = (fileBundle?.path(forResource: resource, ofType: "bundle"))! + "/" + fileName + "." + fileType
do {
return try String(contentsOfFile: filePath)
}
catch let error as NSError {
return error.description
}
}

How to handle symlinks when reading data from a file path in swift

I have a file path as a string. I want to:
Test if there's a file there
Read the contents of the file as a string
the problem I'm having is that sometimes that file path involves a symbolic link (symlink). Maybe to the file itself. Maybe to one of the directories above the file.
[EDIT] closing this because the following code (that I started with), actually works just fine, there were just multiple levels of user error involved. Thanks for the input folks.
func getUserResource(relativeFilePath: String) -> String? {
let fileManager = NSFileManager.defaultManager()
let userFilePath = NSHomeDirectory() + relativeFilePath
if(fileManager.fileExistsAtPath(userFilePath))
{
do {
return try String(contentsOfFile: userFilePath, encoding: NSUTF8StringEncoding);
} catch {
return nil;
}
}
return nil;
}
If you're not sure if the symlink leads to a file or directory, you should be using fileExistsAtPath(path:, isDirectory:). fileExistsAtPath will always return true for a symlink, because technically there is a file at that path. By passing a boolean pointer to isDirectory, you can follow the symlink to a file or to a directory:
Assume symlinkToSomeFile is a symbolic link to a file and symlinkToSomeDir is a symbolic link to a directory.
let symlinkFilePath = NSHomeDirectory() + "/temp/symlinkToSomeFile"
let symlinkDirPath = NSHomeDirectory() + "/temp/symlinkToSomeDir"
var fileCheck: ObjCBool = false
var dirCheck: ObjCBool = false
print(fileManager.fileExistsAtPath(symlinkFilePath, isDirectory: &fileCheck)) // true
print(fileCheck) // false
print(fileManager.fileExistsAtPath(symlinkDirPath, isDirectory: &dirCheck)) // true
print(dirCheck) // true