find a file inside application documents directory - ios

i have copied a video file inside my installed application documents directory using iexplorer and i am trying to play it on avplayer by accessing the video.but i cant found the video.here is my code to find the files under application documents directoy
var paths: [AnyObject] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
var documentsDirectory: String = paths[0] as! String
do {
let filePathsArray: [AnyObject] = try NSFileManager.defaultManager().subpathsOfDirectoryAtPath(documentsDirectory)
print("files array %#", filePathsArray)
}catch {
}
it shows empty

from Apple Docs:
subpathsOfDirectoryAtPath:error:
Performs a deep enumeration of the specified directory and returns
the paths of all of the contained subdirectories.
try iterating thru .contentsOfDirectoryAtPath:error instead

Related

Different path after appendingPathComponent(_:)

I am trying to access json files I copied to the ~/Documents folder.
When I check what files are available there, it has those files in an array with paths beginning with file:///private/var/mobile/Containers/Data/Application/95982B17-2C5F-4E3F-8AD7-FB90F557B991/Documents/:
let fileManager = FileManager.default
if let docDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
do {
let docs = try fileManager.contentsOfDirectory(at: docDirectory, includingPropertiesForKeys: [], options: .skipsHiddenFiles)
print("Files in ~/Documents are: ")
for doc in docs {
print(doc)
}
} catch let error {
Logger.printLogEntry(message: "Could not get content of documents directory: \(error.localizedDescription)", category: .dev
)
}
}
But when I then add a path like so
let filePath = docDirectory.appendingPathComponent("products.json")
print("File Path is: ", filePath)
it gives me the following path: file:///var/mobile/Containers/Data/Application/95982B17-2C5F-4E3F-8AD7-FB90F557B991/Documents/
This is different on the simulator; paths there remain the same (without the private stuff in front...
Can anyone explain that to me? To be clear, I need to copy / access in different methods, so understanding the way it's accessing differently is crucial to me.
So that hopefully for someone else to be more successful to get an answer when researching this:
/var and /private/var` point to the same folder on a real device, as one is an alias of the other, as mentioned in the comments above. So thanks to the commenters for their hints.

Get all URLs for resources in sub-directory in Swift

I am attempting to create an array of URLs for all of the resources in a sub-directory in my iOS app. I can not seem to get to the correct path, I want to be able to retrieve the URLs even if I do not know the names (i.e. I don't want to hard code the file names into the code).
Below is a screen shot of the hierarchy, I am attempting to get all the files in the 'test' folder:
Any help is greatly appreciated, I have attempted to use file manager and bundle main path but to no joy so far.
This is the only code I have currently:
let fileManager = FileManager.default
let path = Bundle.main.urls(forResourcesWithExtension: "pdf", subdirectory: "Files/test")
print(path)
I have also tried this code but this prints all resources, I can't seem to specify a sub-directory:
let fm = FileManager.default
let path = Bundle.main.resourcePath!
do {
let items = try fm.contentsOfDirectory(atPath: path)
for item in items {
print("Found \(item)")
}
} catch {
// failed to read directory – bad permissions, perhaps?
}
Based on an answer from #vadian , The folders were changed from virtual groups to real folders. Using the following code I was able to get a list of resources:
let fileManager = FileManager.default
let path = Bundle.main.resourcePath
let enumerator:FileManager.DirectoryEnumerator = fileManager.enumerator(atPath: "\(path!)/Files/test")!
while let element = enumerator.nextObject() as? String {
if element.hasSuffix("pdf") || element.hasSuffix("jpg") { // checks the extension
print(element)
}
}
Consider that the yellow folders are virtual groups, not real folders (although Xcode creates real folders in the project directory). All files in the yellow folders are moved into the Resources directory in the bundle when the app is built.
Real folders in the bundle are in the project navigator.
You can follow the following steps to get them:
Create a new folder inside your project folder with the extension is .bundle (for example: Images.bundle).
Copy resource files into that new folder.
Drag that new folder into the project that opening in Xcode.
Retrieve the URLs by using the following code snippet:
let urls = Bundle.main.urls(forResourcesWithExtension: nil, subdirectory: "Images.bundle")
You can also view the guide video here: https://youtu.be/SpMaZp0ReEo
I came across a similar issue today. I needed to retrieve the URL of a resource file in a bundle ignoring its path.
I wrote the following:
public extension Bundle {
/// Returns the file URL for the resource identified by the specified name, searching all bundle resources.
/// - Parameter resource: The name of the resource file, including the extension.
/// - Returns: The file URL for the resource file or nil if the file could not be located.
func recurseUrl(forResource resource: String) -> URL? {
let contents = FileManager.default.allContentsOfDirectory(atPath: self.bundlePath)
for content in contents {
let fileNameWithPath = NSString(string: content)
if let fileName = fileNameWithPath.pathComponents.last {
if resource == fileName {
return URL(fileURLWithPath: content)
}
}
}
return nil
}
Based on this:
public extension FileManager {
/// Performs a deep search of the specified directory and returns the paths of any contained items.
/// - Parameter path: The path to the directory whose contents you want to enumerate.
/// - Returns: An array of String objects, each of which identifies a file or symbolic link contained in path. Returns an empty array if the directory does not exists or has no contents.
func allContentsOfDirectory(atPath path: String) -> [String] {
var paths = [String]()
do {
let url = URL(fileURLWithPath: path)
let contents = try FileManager.default.contentsOfDirectory(atPath: path)
for content in contents {
let contentUrl = url.appendingPathComponent(content)
if contentUrl.hasDirectoryPath {
paths.append(contentsOf: allContentsOfDirectory(atPath: contentUrl.path))
}
else {
paths.append(contentUrl.path)
}
}
}
catch {}
return paths
}
}
Which achieves the goal of retrieving the URL for the first match of a given resource filename in a bundle's resources, all directories wide.
I tend to think that Swift's func url(forResource name: String?, withExtension ext: String?) -> URL? should behave this way in the first place.

How to correctly reference/retrieve a temp file created in AppData for file upload to a server?

So the app I'm making creates a file called "logfile" and I'm trying to send that file via Alamofire upload to a server. The file path printed in the console log is
/var/mobile/Containers/Data/Application/3BE13D78-3BF0-4880-A79A-27B488ED9EFE/Documents/logfile.txt
and the file path I can use to manually access the log created in the .xcappdata is
/AppData/Documents/logfile.txt
To access it, I'm using
let fileURL = Bundle.main.url(forResource: "", withExtension: "txt")
where inbetween the double quotes for "forResource", I've tried both file paths I listed in the previous paragraph as well as just the file name but I'm getting a nil value for file found for either. The file isn't recognized to be there, presumably because the file path I'm using is wrong as Alamofire is returning nil when trying to locate send the file. Anyone know the direct file path I'm supposed to use to be able to grab my file since the other two don't supposedly work? Thank you!
Use below code to get string data from text file to upload to server:
let fileName = "logfile"
let documentDirURL = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = documentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
var readString = "" // Used to store the file contents
do {
// Read the file contents
readString = try String(contentsOf: fileURL)
} catch let error as NSError {
print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
}
print("File Text: \(readString)") // Send 'readString' to server
If you're dynamically creating the file at runtime, it won't be in your app bundle so the Bundle class won't be able to find it. The directories you see are also dynamically-generated and not only platform-specific, but also device-specific, so you can't use the file paths directly. Instead, you'll have to ask for the proper directory at runtime from the FileManager class, like this:
guard let documents = FileManager.default.urls(for: .documentsDirectory, in: .userDomainMask).first else{
// This case will likely never happen, but forcing anything in Swift is bad
return
}
let logURL = URL(string: "logfile.txt", relativeTo: documents)
do{
let fileContents = String(contentsOf: logURL)
// Send your file to your sever here
catch{
// Handle any errors you might've encountered
}
Note that I'm guessing based on the paths you pasted in your answer you put it in your application's documents directory. That's a perfectly fine place to put this type of thing, but if I'm wrong and you put it in a different place, you'll have to modify this code to point to the right place

How to store and view the file in Iphone using IOS Swift

I am new to swift and trying to save the file on iphone and view them using file manager app present in app store. but every time the path looks like its getting stored in my mac machine. below is code which i have written for storing a simple text file
func saveImageDocumentDirectory(){
let str = "Super long string here"
let filename = getDocumentsDirectory().appendingPathComponent("output.txt")
do {
try str.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
print(filename.path)
} catch {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
but path at which file is getting stored is printed as below
/var/mobile/Containers/Data/Application/ACBC0B24-XXXX-XXXX-XXXX-BDAA4901EA41/Documents/output.txt

How can I purge just images in cache directory?

I want to clear all images in default cache directory every 1 minute but the cache files do not have extensions to specific their type and I don't know how to delete just images like PNG (not other data).
this is sample code I saw on this site:
let fileManager = FileManager.default
let documentsUrl = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! as NSURL
let documentsPath = documentsUrl.path
do {
if let documentPath = documentsPath
{
let fileNames = try fileManager.contentsOfDirectory(atPath: "\(documentPath)")
print("all files in cache: \(fileNames)")
for fileName in fileNames {
if (fileName.hasSuffix(".png"))
{
let filePathName = "\(documentPath)/\(fileName)"
try fileManager.removeItem(atPath: filePathName)
}
}
let files = try fileManager.contentsOfDirectory(atPath: "\(documentPath)")
print("all files in cache after deleting images: \(files)")
}
} catch {
print("Could not clear temp folder: \(error)")
}
possibility:
you could use ImageIO to test EVERY file before deleting it but that would mean reading it before removing it. It'd replace testing for a suffix BUT
as it'd be really unnecessarily expensive IMHO I wont even provide code.
okay way:
=> Rename your images to have a suffix or prefix so you can identify them by name (n calls)
good way
=> put the images in a seperate folder and just remove the folder to purge them. (1 call)

Resources