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)
Related
I am trying to delete the Core Data generated sqlite3 file for testing purposes in tear down.
Core Data creates the file using the following path.
/Users/mehreen/Library/Developer/CoreSimulator/Devices/62BB2C13-6640-408E-B2B9-0247473E24B4/data/Containers/Data/Application/**8507624D-3A06-4EEC-9C0D-2AAF328E43B6**/Library/Application Support
In my integration test I have the following code to delete the sqlite file in tear down method.
static func rollbackDatabase() {
let fileManager = FileManager.default
let applicationSupportUrl = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first! as NSURL
let applicationSupportPath = applicationSupportUrl.path
do {
let fileNames = try fileManager.contentsOfDirectory(atPath: applicationSupportPath!)
for fileName in fileNames {
let filePath = "\(String(describing: applicationSupportPath))/\(fileName)"
try fileManager.removeItem(atPath: filePath)
}
} catch {
print(error.localizedDescription)
}
}
The problem is that it points to the path
/Users/mehreen/Library/Developer/CoreSimulator/Devices/62BB2C13-6640-408E-B2B9-0247473E24B4/data/Containers/Data/Application/**FEB3A60C-CDC0-4D59-AF67-6D1723C01B1D**/Library/Application Support
which is different from the original Core Data file path. So on that path there are no files to delete. How can I get the same path as used by Core Data to the sqlite files in my test environment.
I need to create a simple zip file with files included without parent directory in swift.
I found a good solution from Robin Kunde https://recoursive.com/2021/02/25/create_zip_archive_using_only_foundation/ but the files have a parent directory in the zip file.
So when you unzip the files, there is a directory with the name e.g. "Documents".
I don't need real compression or other zip features. Our backend server checks the content and the folder must be removed.
I don't think, that this is even possible without a C-library :(
I tried to decode the ZIP-file to UTF-8, delete the folder names and save the data to a file. The file was corrupt.
let fm = FileManager.default
let baseDirectoryUrl = fm.urls(for: .documentDirectory, in: .userDomainMask).first!
let data = try! Data(contentsOf: baseDirectoryUrl.appendingPathComponent("archive.zip"))
let str = String(decoding: data, as: UTF8.self)
let newstr = str.replacingOccurrences(of: "Documents/", with: "")
do {
try newstr.write(to: baseDirectoryUrl.appendingPathComponent("archive_without_parent_name.zip"), atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
I am trying to save an array of CKRecords to the documents directory in
order to have fast startup and offline access.
Downloading the CKRecords from CloudKit works fine and I am able to use the CKAsset in each record without issue. However, when I save the array of CKRecords that I downloaded to a local file, the CKAsset is not included in the data file. I can tell this from the size of the file saved to the documents directory. If I reconstitute the disk file into an array of CKRecords, I can retrieve all of the fields except the CKAsset. Other than the system fields, and the CKAsset field, all of the fields are Strings.
For testing - I have 10 CloudKit records each with six small String fields
and a CKAsset which is about 500KB. When I check the size of the
resulting file in documents the file size is about 15KB.
Here's the function to save the array. AppDelegate.ckStyleRecords is a
static array of the downloaded CKRecords.
func saveCKStyleRecordsToDisk() {
if AppDelegate.ckStyleRecords.count != 0 {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docsDirectoryURL = urls[0]
let ckStyleURL = docsDirectoryURL.appendingPathComponent("ckstylerecords.data")
do {
let data : Data = try NSKeyedArchiver.archivedData(withRootObject: AppDelegate.ckStyleRecords, requiringSecureCoding: true)
try data.write(to: ckStyleURL, options: .atomic)
print("data write ckStyleRecords successful")
} catch {
print("could not save ckStyleRecords to documents directory")
}
}//if count not 0
}//saveCKStyleRecordsToDisk
Here is the function to reconstitute the array.
func checkForExistenceOfCKStyleRecordsInDocuments(completion: #escaping ([CKRecord]) -> Void) {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docsDirectoryURL = urls[0]
let ckStyleURL = docsDirectoryURL.appendingPathComponent("ckstylerecords.data")
var newRecords : [CKRecord] = []
if FileManager.default.fileExists(atPath: ckStyleURL.path) {
do {
let data = try Data(contentsOf:ckStyleURL)
//yes, I know this has been deprecated, but I can't seem to get the new format to work
if let theRecords: [CKRecord] = try NSKeyedUnarchiver.unarchiveObject(with: data) as? [CKRecord] {
newRecords = theRecords
print("newRecords.count is \(newRecords.count)")
}
} catch {
print("could not retrieve ckStyleRecords from documents directory")
}
}//if exists
completion(newRecords)
}//checkForExistenceOfckStyleRecordsInDocuments
Calling the above:
kAppDelegate.checkForExistenceOfCKStyleRecordsInDocuments { (records) in
print("in button press and records.count is \(records.count)")
//this is just for test
for record in records {
print(record.recordID.recordName)
}
AppDelegate.ckStyleRecords = records
}//completion block
Upon refreshing the tableView that uses the ckStyleRecords array, all data
seems correct except the CKAsset (which in this case is a SceneKit
scene) is of course missing.
Any guidance would be appreciated.
A CKAsset was just a file reference. the fileURL property of the CKAsset is where the actual file is located. If you save a SKAsset then you only save the reference to the file. When doing that you do have to remember that this url is on a cache location which could be cleared if you are low on space.
You could do 2 things.
1. when reading your backup CKAsset, then also check if the file is located at the fileURL location. If the file is not there, then read it again from CloudKit.
2. Also backup the file from the fileURl to your documents folder. When you read your CKAsset from your backup, then just don't read the file from fileURL but the location where you have put it in your documents filter.
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.
I created a file in the document directory and for some reason when I try to delete it using the code below, it doesn't get deleted. The code doesn't throw any errors, but the file is still there
let fileManager = FileManager.default
if let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let filePath = documentDirectory.appendingPathComponent("data.json")
do {
try fileManager.removeItem(atPath: filePath.path)
} catch let error as NSError {
print(error.localizedDescription)
}
}
I also tried to put it inside another folder and remove the folder but still the same problem.
This is the path where the file is stored :
Users/user1/Library/Developer/CoreSimulator/Devices/76AFDB69-75C8-464E-93F2-6ABF622068FD/data/Containers/Data/Application/7D268156-977A-4A3C-834B-6B13FA3DE76D/Documents/
you can try like below
if let filePath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("data.json"), fileManager.fileExists(atPath: filePath.path) {
do {
try fileManager.removeItem(atPath: filePath.path)
} catch let error as NSError {
print(error.localizedDescription)
}
}
The code doesn't throw any errors, but the file is still there
No, it isn't. The problem is with the way you are checking to see whether "the file is still there". You are looking on your computer for the file. But iOS files are sandboxed. At the time you are looking, the path where the file was is completely different from your claimed path:
Users/user1/Library/Developer/CoreSimulator/Devices/76AFDB69-75C8-464E-93F2-6ABF622068FD/data/Containers/Data/Application/7D268156-977A-4A3C-834B-6B13FA3DE76D/Documents/
Such paths are not permanent. They are meaningless and should not be used. The only way to know whether the file is still there is with more code from inside iOS, i.e. ask the FileManager. When you do, you will find that you are, indeed, deleting the file successfully.