Different path URL for FileManager everytime I open the app
You are using the wrong API. absoluteString
(in rootURL.absoluteString
) returns the string representation including the scheme file://
. The correct API for file system URLs is path
I recommend to use the URL related API as much as possible
public func directoryExists(at url: URL) -> Bool {
let fileManager = FileManager.default
var isDir : ObjCBool = false
if fileManager.fileExists(atPath: url.path, isDirectory:&isDir) {
return isDir.boolValue
} else {
return false
}
}
and compose the URL in a more reliable way
func createARObjectDirectory() {
let rootURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
if directoryExists(at: rootURL.appendingPathComponent(DefaultURL.arObjectUrlDirectoryName) {
Logger.logServer("ARObject directly found")
} else {
createNewDirectory(name: DefaultURL.arObjectUrlDirectoryName)
}
}
And this is swiftier too
public func createNewDirectory(name: String) {
let documentDirectory = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let dirURL = documentDirectory.appendingPathComponent(name)
do
{
try FileManager.default.createDirectory(at: dirURL, withIntermediateDirectories: false, attributes: nil)
}
catch let error as NSError
{
Logger.logError("Unable to create directory \(error.debugDescription)")
}
Logger.logInfo("Dir Path = \(dirPath.path)")
}
iOS file path is changing at every launch/rerun the application
Edit 1:
Hi I created the new project and use the same code I posted in main, and it's working. But in the real project it not working.
Not sure what exactly going on in your project, try to debug it. It's part of development as well. :)
If you are in hurry to fix this issue in this weekend try to use the following code snippet.
// collect data from bundle
let constFileURL = Bundle.main.url(forResource: "AppConst", withExtension: "json")!
let data = try! Data(contentsOf: constFileURL)
// try to write data in document directory
do {
let constFileURL = try saveFileInDocumentDirectory(filePath: "MyFolder/AppConst.json", data: data)
// use your `constFileURL`
} catch (let error as FileOperationError) {
switch error {
case .fileAlreadyExists(let url):
let data = try! Data(contentsOf: url)
print(String(data: data, encoding: .utf8))
case .IOError(let error):
print("IO Error \(error)")
}
} catch {
print("Unknown Error \(error)")
}
// Helpers
enum FileOperationError: Error {
case fileAlreadyExists(url: URL)
case IOError(Error)
}
func saveFileInDocumentDirectory(filePath: String, data: Data) throws -> URL {
// final destination path
let destURLPath = fullURLPathOf(filePath, relativeTo: .documentDirectory)
// check for file's existance and throw error if found
guard FileManager.default.fileExists(atPath: destURLPath.path) == false else {
throw FileOperationError.fileAlreadyExists(url: destURLPath)
}
// Create Intermidiate Folders
let intermidiateDicPath = destURLPath.deletingLastPathComponent()
if FileManager.default.fileExists(atPath: intermidiateDicPath.path) == false {
do {
try FileManager.default.createDirectory(at: intermidiateDicPath, withIntermediateDirectories: true, attributes: nil)
} catch {
throw FileOperationError.IOError(error)
}
}
// File Writing
do {
try data.write(to: destURLPath, options: .atomic)
} catch {
throw FileOperationError.IOError(error)
}
return destURLPath
}
func fullURLPathOf(_ relativePath: String, relativeTo dic:FileManager.SearchPathDirectory ) -> URL {
return FileManager.default.urls(for: dic, in: .userDomainMask).first!.appendingPathComponent(relativePath)
}
Original Answer
Why don't you just return "MyFolder/\(fileName)"
on successful file operation? If you need to access the path later you can always do that using FileManager
APIs.
let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let constFilePath = docDir.appendingPathComponent("MyFolder/\(fileName)")
// Access const file data
do {
let fileData = try Data(contentsOf: constFilePath)
// Use you data for any further checking
} catch {
// Error in reading file data
print("Error in file data access : \(error)")
}
Document directory path change when rebuild application
iOS 8 onwards, Absolute url to app's sandbox changes every time you relaunch the app. Hence you should never save the absolute url of the video. Save the name of the video and recreate the url every time you relaunch the app.
let pathComponent = "pack\(self.packID)-\(selectRow + 1).mp4"
let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let folderPath: URL = directoryURL.appendingPathComponent("Downloads", isDirectory: true)
let fileURL: URL = folderPath.appendingPathComponent(pathComponent)
Once you have fileURL
look for the file and you will find the file downloaded in previous launch.
iOS creates a new Sandbox for app every time user launches the app. Hence absolute URL will very. But iOS will take care of setting up all the folders and contents inside the Sandbox as it was earlier. So though base url of SandBox change, relative url's of all the content will be remained intact.
Hence its advised never to save absolute url to any folder :) Hope it helps
How can i open default Files app with myapp folder programmatically?
You can open Files
app in specific folder using shareddocuments:
URL scheme and providing file path.
Example:
func getDocumentsDirectory() -> URL { // returns your application folder
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
let path = getDocumentsDirectory().absoluteString.replacingOccurrences(of: "file://", with: "shareddocuments://")
let url = URL(string: path)!
UIApplication.shared.open(url)
P.S:
For more information, read this article.
How to retrieve nested file with FileManager?
I think that you misunderstood the answer in other question.
You want to get this path:
/Library/Application Support/com.Company.DemoApp/Feed/FileStack/I-Want-This-File
/Library/Application Support/
this is the part you can't save anywhere and you have to get it during runtime from FileManager. This is because you have no control over this path and it can change without your approval. You want paths in your application to be relative to this folder.
com.Company.DemoApp/Feed/FileStack/I-Want-This-File
this is part of that file path that you can store in database/config files. This path will change only when you change it. So If you update your application and change paths you can also change paths in database.
This is rough example how it can be implemented:
enum DataDirectoryType : String
{
case wantedFile = "Feed/FileStack/I-Want-This-File-Path"
case anotherFiles = "Feed/AnotherFiles/"
}
extension FileManager {
/// APPLICATION SUPPORT DIRECTORY
static private func createOrFindApplicationSupportDirectory() -> URL? {
let bundleID = Bundle.main.bundleIdentifier
// Find the application support directory in the home directory.
let appSupportDir = self.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
guard appSupportDir.count > 0 else {
return nil
}
// Append the bundle ID to the URL for the Application Support directory.
return appSupportDir[0].appendingPathComponent(bundleID!)
}
static func createOrFindFilePath(_ type : DataDirectoryType ) -> URL? {
guard let appSupportDir = createOrFindApplicationSupportDirectory() else {
return nil
}
let dirPath = appSupportDir.appendingPathComponent(type.rawValue)
// If the directory does not exist, this method creates it.
do {
try self.default.createDirectory(at: dirPath, withIntermediateDirectories: true, attributes: nil)
return dirPath
} catch let error {
print("Error creating Favorites directory with error: \(error)")
return nil
}
}
}
let urlToWantedFile = FileManager.createOrFindFilePath(.wantedFile)
Related Topics
How to Call a Func Within a Closure
Ios13 Uialertcontroller with Custom View & Preferredstyle as Actionsheet Grayscale All Colors
Create a Weak Container in Swift That Accepts a Native Swift Protocol
Advancedby' in Swift Is Unavailable
How to Integrate Mapbox Sdk with Swiftui
Requestaccessformediatype Doesn't Ask for Permission
How to Filter Nsarray in Swift
How to Read Code Block After a Function Call
Convert Swift Encodable Class Typed as Any to Dictionary
How to Decode Partially Double Serialized JSON String Using 'Codable' Protocol
Accessing Struct from One Class to Another
Alamofire 5 Escaping Forward Slashes
Rotation Gesture Produces Undesired Rotation
Tube Physics Body Acting Like Scncylinder, But How to Make It Act Like Scntube
How to Use the Optional Variable in a Ternary Conditional Operator
Check Whether the Arreferenceimage Is No Longer Visible in the Camera's View