Different Path Url for Filemanager Everytime I Open the App

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



Leave a reply



Submit