How do I get the path of the "/Library/Containers/" directory - swift

A sandboxed MacOS app can easily access data in two folders ...
~/Library/Containers/ProgramName/
~/Library/Group Containers/SecurityGroupName/
The following code will give me the "~/Library/Group Container/" path ...
let fileManager = FileManager.default
let directory = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "myGroup")
print("path:",directory)
This will print:
"path: /Users/myName/Library/Group Containers/myGroup"
I want to get the path of the "~/Library/Containers/" directory, not the "~/Library/Group Containers/" directory.
This must be easy to do, as it is a common directory.
Does anybody know how to do this using a swift function.
I know I can just create it with ...
var path: String = "/Users/etc/Containers/" + programName
Ian

In the sandbox the API
let url = try FileManager.default.url(for: .libraryDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false)
points to the user library of the container of the current app.
file:///Users/myself/Library/Containers/com.myself.Greatapp/Data/Library/
You don't have access to the higher level folder ~/Library/Containers

Related

Cannot create sqlite file with SQLite.swift "cannot open file at line..."

I'm attempting to create a sqlite DB file within my iOS project. I'm using the code as documented for R/W
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
let db = try Connection("\(path)/db.sqlite3")
but I end up with a cannot open file at line 45340 of [d24547a13b].
The closest resource I've found is Why do I get Unable to Open Database file? but the code there seems to be the same as what I have.
edit: More logs
[logging-persist] os_unix.c:45340: (0) open
- Undefined error: 0
DB file needs to be created under the documents directory. See Brando Flores' answer: https://stackoverflow.com/a/70514807/346676
do {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let dbFile = "\(path.first ?? "")/db.sqlite3"
print(dbFile) // show full file path
db = try Connection(dbFile)
}
catch {
print(error)
}

Is there a mutual folder where I can save and load data using a simulator or my device?

I'm currently saving my data in Document Directory, using this code :
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let archiveURL = documentsDirectory.appendingPathComponent("myData").appendingPathExtension("plist")
let pListEncoder = PropertyListEncoder()
if let encodedTableArray = try? pListEncoder.encode(myData) {
try? encodedTableArray.write(to: archiveURL, options: .noFileProtection)
}
When I print documentsDirectory, whether my app is running on a simulator or my device (plugged to my computer), paths are not similar :
file:///Users/userName/Library/Developer/CoreSimulator/Devices/E80B48AB-C269-48ED-9AF4-AC55C34C911E/data/Containers/Data/Application/D3C87E08-DC0E-4F53-ABC7-C930DFAC4EF8/Documents/
file:///var/mobile/Containers/Data/Application/F5BE0EB0-F2C7-4842-B039-01D5F8CCA4A2/Documents/ ,
respectively.
Is there a path that can be accessed by both simulators and devices ?
PS : I'm using this path just because I read that it's supposed to be the most appropriate path when saving my kind of data (something like a list of tables), I'm still learning about persistency so I'm not fully understanding why however.
Thank you for your help !

Access root file created by script Swift

From this question: How can I get all image names in asset catalog group?
I want to access a file created in the root of an App in Swift.
My App is called Challenge and my script is
# Type a script or drag a script file from your workspace to insert its path.
#!/bin/sh
>./Challenge/fileNames.txt
for FILE in ./Challenge/Images.xcassets/actions/*; do
echo $FILE >> ./Challenge/fileNames.txt
done
I have tried
let fileManager = FileManager.default
let imagePath = Bundle.main.resourcePath! + "fileNames.txt"
let imageNames = try! fileManager.contentsOfDirectory(atPath: imagePath)
And many other combinations .
This is not homework, I have tried various solutions but as I am not sure where the file is within the file system (how the root can be accessed within the App) I seem unable to locate the file.
Question: How to read ./Challenge/fileNames.txt from an App called challenger, created by a script during the build phase.
The file is located in the main bundle folder, not resource path:
let fileManager = FileManager.default
let imagePath = Bundle.main.path(forResource: "fileName", ofType: "txt")
let content = try! String(contentsOfFile: imagePath)

Read all files from a directory?

I am trying to create a folder in my assets, then get a list of files inside.
Sounds simple but there is no clean answer on how to do exactly this.
Even to get the list from the main directory, most people can't do on Swift 3, reading here : Getting list of files in documents folder
using :
let fileMngr = FileManager.default;
// Full path to documents directory
let docs = fileMngr.urls(for: .documentDirectory, in: .userDomainMask)[0].path
// List all contents of directory and return as [String] OR nil if failed
return try? fileMngr.contentsOfDirectory(atPath:docs)
Not working.
Reading from a specific folder, I couldn't understand how to get it's path for swift.
Any example that really work that reads from a folder ?
If you want to get all files in a personal directory, here is the simple answer
do {
let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let Path = documentURL.appendingPathComponent("yourDirectoyName").absoluteURL
let directoryContents = try FileManager.default.contentsOfDirectory(at: Path, includingPropertiesForKeys: nil, options: [])
}
catch {
print(error.localizedDescription)
}
And then if you want for example to read all files with special extension, you can do it that way
static func listAllFileNamesExtension(nameDirectory: String, extensionWanted: String) -> (names : [String], paths : [URL]) {
let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let Path = documentURL.appendingPathComponent(nameDirectory).absoluteURL
do {
try FileManager.default.createDirectory(atPath: Path.relativePath, withIntermediateDirectories: true)
// Get the directory contents urls (including subfolders urls)
let directoryContents = try FileManager.default.contentsOfDirectory(at: Path, includingPropertiesForKeys: nil, options: [])
// if you want to filter the directory contents you can do like this:
let FilesPath = directoryContents.filter{ $0.pathExtension == extensionWanted }
let FileNames = FilesPath.map{ $0.deletingPathExtension().lastPathComponent }
return (names : FileNames, paths : FilesPath);
} catch {
print(error.localizedDescription)
}
return (names : [], paths : [])
}
So if you want to have all your json files in your personal directory
let allJsonNamePath = listAllFileNamesExtension(nameDirectory:"yourDirectoryName", extensionWanted: "json")
Swift 4/5
let documentDirectoryPath:String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let myFilesPath = "\(documentDirectoryPath)/myfolder"
let filemanager = FileManager.default
let files = filemanager.enumerator(atPath: myFilesPath)
while let file = files?.nextObject() {
print(file)
}
Actually, amazingly, for 2 days no one could tell me the real issue here.
Creating a group, is completely different from dragging a folder into the project.
For some reason, with Apple, its always complicated with files. I have to figure out the NOT so intuitive approach that a group that looks like a folder, is nothing but a nice way to look at something, and will not create a real folder accessible by the file manager.
This strange approach is maybe intutitive to a very pro programmer, but really not to any simple person.
Simply put, create a blue folder outside Xcode and drag it in.

Where do I get the OSX volume for replacing "/" [duplicate]

When using
let directoryEnumerator = FileManager().enumerator(at: ...
in Swift 3, I get all files from the folder, e.g.
"file:///Volumes/MacOS/fasttemp/Fotos/"
The results are not including the leading path (here "/Volumes/MacOS"). So I get
"file:///fasttemp/Fotos/2005/"
How can I get the fullpath (directly from the enumerator) or convert them. I want to use URL functions, not string function manipulating by assumptions.
If "MacOS" is the name of your current startup disk then "/Volumes/MacOS" is a symbolic link to "/", so both "/fasttemp/Fotos/2005/" and "/Volumes/MacOS/fasttemp/Fotos/" are absolute paths to the same file.
In order to get a unique file name representation you can query
a URL for its canonical path. Example:
let url = URL(fileURLWithPath: "/Volumes/MacOS/Applications/Utilities/")
if let cp = (try? url.resourceValues(forKeys: [.canonicalPathKey]))?.canonicalPath {
print(cp)
}
// Output: "/Applications/Utilities"
This requires macOS 10.12/iOS 10 or later. On older systems you can
use the realpath() system call:
if let rp = url.withUnsafeFileSystemRepresentation ({ realpath($0, nil) }) {
let fullUrl = URL(fileURLWithFileSystemRepresentation: rp, isDirectory: true, relativeTo: nil)
free(rp)
print(fullUrl.path)
}
// Output: "/Applications/Utilities"
Note that you want to use URL wherever possible, from the NSURL documentation:
URL objects are the preferred way to refer to local files. Most
objects that read data from or write data to a file have methods that
accept an NSURL object instead of a pathname as the file reference.
Here’s an example of how to get all the objects from a directory:
import Foundation
let manager = FileManager.default
// Get URL for the current user’s Documents directory
// Use URL instead of path, it’s more flexible and preferred
if let documents = manager.urls(for: .documentDirectory, in: .userDomainMask).first,
// Get an Enumerator for the paths of all the objects in the directory
// but do not descend into directories or packages
let directoryEnumerator = manager.enumerator(at: documents, includingPropertiesForKeys: [URLResourceKey.pathKey], options: [.skipsSubdirectoryDescendants, .skipsPackageDescendants]) {
// iterate through the objects (files, directories, etc.) in the directory
for path in directoryEnumerator {
print(path)
}
}