How can I get the file creation date using URL resourceValues method in Swift 3?
You can extend URL as follow:
extension URL {
/// The time at which the resource was created.
/// This key corresponds to an Date value, or nil if the volume doesn't support creation dates.
/// A resource’s creationDateKey value should be less than or equal to the resource’s contentModificationDateKey and contentAccessDateKey values. Otherwise, the file system may change the creationDateKey to the lesser of those values.
var creation: Date? {
get {
return (try? resourceValues(forKeys: [.creationDateKey]))?.creationDate
}
set {
var resourceValues = URLResourceValues()
resourceValues.creationDate = newValue
try? setResourceValues(resourceValues)
}
}
/// The time at which the resource was most recently modified.
/// This key corresponds to an Date value, or nil if the volume doesn't support modification dates.
var contentModification: Date? {
get {
return (try? resourceValues(forKeys: [.contentModificationDateKey]))?.contentModificationDate
}
set {
var resourceValues = URLResourceValues()
resourceValues.contentModificationDate = newValue
try? setResourceValues(resourceValues)
}
}
/// The time at which the resource was most recently accessed.
/// This key corresponds to an Date value, or nil if the volume doesn't support access dates.
/// When you set the contentAccessDateKey for a resource, also set contentModificationDateKey in the same call to the setResourceValues(_:) method. Otherwise, the file system may set the contentAccessDateKey value to the current contentModificationDateKey value.
var contentAccess: Date? {
get {
return (try? resourceValues(forKeys: [.contentAccessDateKey]))?.contentAccessDate
}
// Beginning in macOS 10.13, iOS 11, watchOS 4, tvOS 11, and later, contentAccessDateKey is read-write. Attempts to set a value for this file resource property on earlier systems are ignored.
set {
var resourceValues = URLResourceValues()
resourceValues.contentAccessDate = newValue
try? setResourceValues(resourceValues)
}
}
}
usage:
print(yourURL.creationDate)
Sorting arrays of file attributes by their creation date in Swift
You should not use multiple arrays for this but instead wrap your values in a custom struct
struct FileInfo {
let url: URL
let name: String
let path: String //this is not really needed, you can get it from the url
let date: Date
}
and have one array for this
var files: [FileInfo]()
and create your struct instance and append it
files.append(FileInfo(url: fileURL, name: name, path: path, date: date)
Sorting will now be trivial so after the for loop you do
files.sort(by: { $0.date < $1.date })
This sorts in ascending order, not sure which one you want.
How to get iOS APP archive date using Swift
You can get the url of your app using Bundle property executableURL and use url method resourceValues to get the bundle creation date:
if let executableURL = Bundle.main.executableURL,
let creation = (try? executableURL.resourceValues(forKeys: [.creationDateKey]))?.creationDate {
print(creation)
}
Swift 2 iOS - get file list sorted by creation date - more concise solution?
A possible solution:
if let urlArray = try? NSFileManager.defaultManager().contentsOfDirectoryAtURL(directory,
includingPropertiesForKeys: properties, options:.SkipsHiddenFiles) {
return urlArray.map { url -> (String, NSTimeInterval) in
var lastModified : AnyObject?
_ = try? url.getResourceValue(&lastModified, forKey: NSURLContentModificationDateKey)
return (url.lastPathComponent!, lastModified?.timeIntervalSinceReferenceDate ?? 0)
}
.sort({ $0.1 > $1.1 }) // sort descending modification dates
.map { $0.0 } // extract file names
} else {
return nil
}
The array of URLs is mapped to an array of (lastPathComponent, lastModificationDate)
tuples first, then sorted according to the
last modification date, and finally the path name extracted.
The attributesDictionary
can be avoided by using getResourceValue(_ : forKey)
to retrieve only the last modification date.
Update for Swift 3:
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
if let urlArray = try? FileManager.default.contentsOfDirectory(at: directory,
includingPropertiesForKeys: [.contentModificationDateKey],
options:.skipsHiddenFiles) {
return urlArray.map { url in
(url.lastPathComponent, (try? url.resourceValues(forKeys: [.contentModificationDateKey]))?.contentModificationDate ?? Date.distantPast)
}
.sorted(by: { $0.1 > $1.1 }) // sort descending modification dates
.map { $0.0 } // extract file names
} else {
return nil
}
How to sort the filemanager array by creation date
You need to declare a struct
that has a URL (or filename String) and a Date. Populate an array of this struct from the files (and their creation dates) you query from FileManager.
Use that array of struct as your data model for the table view. You can sort the array on filename or date (or any other attributes you might add in the future).
You can get the creation date of each file by first adding [.creationDateKey]
to the includingPropertiesForKeys
parameter of contentsOfDirectory
. Then access the creation date using resourceValues
on each URL. See How can I get the file creation date using URL resourceValues method in Swift 3? for more details on getting the creation date.
It may help to use the enumerator
method of FileManager
instead of contentsOfDirectory
. This will make it easier to get the needs URL attributes and populate the array of struct.
Files date from directory folder
It's highly recommended to use the URL
related API of FileManager
to get the file attributes in a very efficient way.
This code prints all URLs of the specified directory with a creation date older than a week ago.
let calendar = Calendar.current
let aWeekAgo = calendar.date(byAdding: .day, value: -7, to: Date())!
do {
let directoryContent = try fileManager.contentsOfDirectory(at: directoryURL, includingPropertiesForKeys: [.creationDateKey], options: .skipsHiddenFiles)
for url in directoryContent {
let resources = try url.resourceValues(forKeys: [.creationDateKey])
let creationDate = resources.creationDate!
if creationDate < aWeekAgo {
print(url)
// do somthing with the found files
}
}
}
catch {
print(error)
}
If you want finer control of the workflow for example an URL is invalid and you want to print the bad URL and the associated error but continue precessing the other URLs use an enumerator, the syntax is quite similar:
do {
let enumerator = fileManager.enumerator(at: directoryURL, includingPropertiesForKeys: [.creationDateKey], options: [.skipsSubdirectoryDescendants, .skipsHiddenFiles], errorHandler: { (url, error) -> Bool in
print("An error \(error) occurred at \(url)")
return true
})
while let url = enumerator?.nextObject() as? URL {
let resources = try url.resourceValues(forKeys: [.creationDateKey])
let creationDate = resources.creationDate!
if creationDate < last7Days {
print(url)
// do somthing with the found files
}
}
}
catch {
print(error)
}
Get file size in Swift
Use attributesOfItemAtPath
instead of attributesOfFileSystemForPath
+ call .fileSize() on your attr.
var filePath: NSString = "your path here"
var fileSize : UInt64
var attr:NSDictionary? = NSFileManager.defaultManager().attributesOfItemAtPath(filePath, error: nil)
if let _attr = attr {
fileSize = _attr.fileSize();
}
In Swift 2.0, we use do try catch pattern, like this:
let filePath = "your path here"
var fileSize : UInt64 = 0
do {
let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)
if let _attr = attr {
fileSize = _attr.fileSize();
}
} catch {
print("Error: \(error)")
}
In Swift 3.x/4.0:
let filePath = "your path here"
var fileSize : UInt64
do {
//return [FileAttributeKey : Any]
let attr = try FileManager.default.attributesOfItem(atPath: filePath)
fileSize = attr[FileAttributeKey.size] as! UInt64
//if you convert to NSDictionary, you can get file size old way as well.
let dict = attr as NSDictionary
fileSize = dict.fileSize()
} catch {
print("Error: \(error)")
}
Check if NSURL is a directory
that is working quote well on my side:
var error: NSError?
let documentURL : NSURL = NSFileManager.defaultManager().URLForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomain: NSSearchPathDomainMask.UserDomainMask, appropriateForURL: nil, create: true, error: &error)
var isDirectory: ObjCBool = ObjCBool(0)
if NSFileManager.defaultManager().fileExistsAtPath(documentURL.path, isDirectory: &isDirectory) {
println(isDirectory)
}
NOTE: it checks whether the Documents
folder is a folder. you can replace the URL with anything, of course.
Related Topics
Swiftui - Is There a Popviewcontroller Equivalent in Swiftui
Iboutlet of Another View Controller Is Nil
Using Combine's Future to Replicate Async Await in Swift
How to Make an Array of the Current Week Dates Swift
How to Generate Large, Ranged Random Numbers in Swift
Swift Performsegue Going to Xcode
Swift Struct Type Recursive Value
How to Use Generic Types to Get Object with Same Type
How to Get the File Creation Date Using Url Resourcevalues Method in Swift 3
Swiftui: Can't Get the Transition of a Detailview to a Zstack in the Mainview to Work
Apply a Shadow on a Uiview That Have Same Corner Radius Than View
Why Isn't Guard Let Foo = Foo Valid
Xcode 9 and Xcode 10 Giving Different Results, Even with Same Swift Version
Swift Setter Causing Exc_Bad_Access
Swift Dictionary Default Value
How to Animate a Model's Rotation in Realitykit
Try, Try! & Try? What's the Difference, and When to Use Each