I just drag the Data.csv file to the application folder in the Navigator panel, I am trying to set the correct path of the file into the app. The code below I used for the simulator and works perfect, but to run in the device I changed to the second block of code, then I got this errors:
Data[399:157757] CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
Error Domain=NSCocoaErrorDomain Code=256 "The file “Documents” couldn’t be opened." UserInfo={NSURL=/var/mobile/Containers/Data/Application/C7756542-6922-4C6F-A98E-C6F407B2063E/Documents}
//code to show the path in the simulator:
guard let remoteURL = NSURL(string: "/Users/mbp/Library/Developer/CoreSimulator/Devices/7F25FC7C-F2B2-464E-85B4-A2B96DB83F17/data/Containers/Bundle/Application/F285940D-7776-4EE2-83A1-D54DD3411E0E/Data.app/Data.csv") else {
return
}
Block to run the app in the device:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let sourcePath = NSBundle.mainBundle().pathForResource(“Data”, ofType: "csv")
print(sourcePath)
let filename = "Data.csv"
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let destinationPath = documentsPath + "/" + filename
do {
try NSFileManager().copyItemAtPath(sourcePath!, toPath: destinationPath)
} catch _ {
}
Try to load the file
let fetchRequest: NSFetchRequest = NSFetchRequest(entityName: "DataEntity")
fetchRequest.fetchLimit = 1
do {
let result = try managedObjectContext.executeFetchRequest(fetchRequest)
if result.count == 0 {
preloadData()
}
} catch let error as NSError {
print("Error: \(error.domain)")
}
func preloadData () {
guard let remoteURL = NSURL(string:NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]) else {
return
}
}
Process file path via NSURL can avoid the mismatch between device and simulator.
let srcURL = NSBundle.mainBundle().URLForResource("Data", withExtension: "csv")!
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
var toURL = NSURL(string: "file://\(documentsPath)")!
toURL = toURL.URLByAppendingPathComponent(srcURL.lastPathComponent!)
do {
try NSFileManager().copyItemAtURL(srcURL, toURL: toURL)
self.preloadData(toURL)
} catch let error as NSError {
print(error.localizedDescription)
}
func preloadData(toURL: NSURL) {
print("=== Success and print toURL ===")
print(toURL)
}
Related
I have already copy the file absolute path and paste in simulator browser, the image can be opened. But the fileExists is fail, i dont know why..... Can anyone help
let defaultImage = "302C3FA1-E4E1-4CD8-B6DF-2FF4E4E24C11.jpeg"
loadImage(at: defaultImage)
func fileExists(at path: String) -> Bool {
return FileManager.default.fileExists(atPath: path)
}
func loadImage(at path: String) -> UIImage? {
let tempPath = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let imagePath = "\(tempPath)\(path.trimmingCharacters(in: .whitespacesAndNewlines))"
guard fileExists(at: imagePath) else { return nil }
guard let image = UIImage(contentsOfFile: imagePath) else { return nil }
return image
}
You need split filename and extension filename.
If you use main bundle. you can follow this code
let stringPath = Bundle.main.path(forResource: "your_filename", ofType: "txt")
let urlPath = Bundle.main.url(forResource: "your_filename", withExtension: "txt")
or you can use my code.
func readConfigFromBundle(fileExtension: String) -> TCBConfigure? {
let bundle = Bundle.main
if let resPath = bundle.resourcePath {
do {
let dirContents = try FileManager.default.contentsOfDirectory(atPath: resPath)
let filteredFiles = dirContents.filter { $0.contains(fileExtension) }
for fileName in filteredFiles {
let sourceURL = bundle.bundleURL.appendingPathComponent(fileName)
let data: NSData? = NSData.init(contentsOf: sourceURL)
if let fileData = data {
// implement your logic
}
}
} catch {
// implement when error
}
}
return nil
}
The cache.db-wal file have the sensitive information in my application.Need to remove the cache files in Caches directory.
This should work for you.
let fileManager = NSFileManager.defaultManager()
let documentsUrl = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first! as NSURL
let documentsPath = documentsUrl.path
do {
if let documentPath = documentsPath
{
let fileNames = try fileManager.contentsOfDirectoryAtPath("\(documentPath)")
for fileName in fileNames {
if (fileName == "cache.db-wal")
{
let filePathName = "\(documentPath)/\(fileName)"
try fileManager.removeItemAtPath(filePathName)
}
}
let files = try fileManager.contentsOfDirectoryAtPath("\(documentPath)")
}
} catch {
print("Could not clear: \(error)")
}
In swift 3.1
** In my case i wanted to remove JSON data through the folder so i named it as "fsCachedData" you can change name accordingly..**
func removeCache() {
let caches = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0])
let appId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String
let path = String(format:"%#/%#/Cache.db-wal",caches, appId)
do {
try FileManager.default.removeItem(atPath: path)
} catch {
print("ERROR DESCRIPTION: \(error)")
}
}
swift 4
func removeNetworkDictionaryCache() {
let caches = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0])
let appId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String
let path = String(format:"%#/%#/Cache.db-wal",caches, appId)
do {
try FileManager.default.removeItem(atPath: path)
} catch {
print("ERROR DESCRIPTION: \(error)")
}
}
In Swift 5.2 solution (Just converted code)
func removeNetworkCache() {
let caches = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0])
let appId = Bundle.main.infoDictionary!["CFBundleIdentifier"] as! String
let path = String(format:"%#/%#/Cache.db-wal",caches, appId)
do {
try FileManager.default.removeItem(atPath: path)
} catch {
print("ERROR DESCRIPTION: \(error)")
}
}
I could find a solution for the above question.
func removeNetworkCache() {
let caches = (NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0])
let appId = NSBundle.mainBundle().infoDictionary!["CFBundleIdentifier"] as! String
let path = String(format:"%#/%#/Cache.db-wal",caches, appId)
do {
try NSFileManager.defaultManager().removeItemAtPath(path)
} catch {
print("ERROR DESCRIPTION: \(error)")
}
}
I know how to get a remote URL in Swift
let remoteURL = NSURL(string: "https://myserver/file.txt")!
I know how to get a local URL in Swift
let localURL = NSURL(fileURLWithPath: documentsFolder + "/my_local_file.txt")
and unfortunately this does not work
NSFileManager.defaultManager().copyItemAtURL(remoteURL, toURL: localURL)
with the following error
The file “file.txt” couldn’t be opened because URL type https isn’t supported.
Is there a way how to perform this?
You can use NSURLSessionDownloadTask to download the file:
func downloadFile(url: URL) {
let downloadRequest = URLRequest(url: url)
URLSession.shared.downloadTask(with: downloadRequest) { location, response, error in
// To do check resoponse before saving
guard let tempLocation = location where error == nil else { return }
let documentDirectory = FileManager.default.urlsForDirectory(.documentDirectory, inDomains: .userDomainMask).last
do {
let fullURL = try documentDirectory?.appendingPathComponent((response?.suggestedFilename!)!)
try FileManager.default.moveItem(at: tempLocation, to: fullURL!)
print("saved at \(fullURL) ")
} catch NSCocoaError.fileReadNoSuchFileError {
print("No such file")
} catch {
// other errors
print("Error downloading file : \(error)")
}
}.resume()
}
let stringURL = "https://wordpress.org/plugins/about/readme.txt"
downloadImage(url: URL(string: stringURL)!)
Update: SWIFT 2.2
func downloadFile(url: NSURL) {
let downloadRequest = NSURLRequest(URL: url)
NSURLSession.sharedSession().downloadTaskWithRequest(downloadRequest){ (location, response, error) in
guard let tempLocation = location where error == nil else { return }
let documentDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first
let fullURL = documentDirectory?.URLByAppendingPathComponent((response?.suggestedFilename)!)
do {
try NSFileManager.defaultManager().moveItemAtURL(tempLocation, toURL: fullURL!)
} catch NSCocoaError.FileReadNoSuchFileError {
print("No such file")
} catch {
print("Error downloading file : \(error)")
}
}.resume()
}
let stringURL = "https://wordpress.org/plugins/about/readme.txt"
let url = NSURL.init(string: stringURL)
downloadFile(url!)
You should download it first, then save it to a local file.
Code example can be found here: (using AFNetworking)
How I properly setup an AFNetworking Get Request?
I'm making an app that records video, uploads it to iCloud using CloudKit with a CKAsset, then downloads the file and plays it in an AVPlayer. This is all written in Swift 2.0
I have gotten the data downloaded, and I think I've been able to reference it but I'm not sure. Data/garbage does print when I convert the URL into an NSData object and print it to the console. The video files gets downloaded as a binary file however. I was able to go to the CloudKit dashboard and download the file and append '.mov' to it, and it opened in Quicktime no problem.
So I think my main issue is that I can't work out how to get the video file to actually play, since the file has no extension. I have tried appending '.mov' to the end with URLByAppendingPathExtension() to no avail. Let me know of any ideas!
Upload Video
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let tempURL = info[UIImagePickerControllerMediaURL] as! NSURL
dismissViewControllerAnimated(true) { () -> Void in
self.uploadVideoToiCloud(tempURL)
print("\n Before Upload: \(tempURL)\n")
}
}
func uploadVideoToiCloud(url: NSURL) {
let videoRecord = CKRecord(recordType: "video", recordID: id)
videoRecord["title"] = "This is the title"
let videoAsset = CKAsset(fileURL: url)
videoRecord["video"] = videoAsset
CKContainer.defaultContainer().privateCloudDatabase.saveRecord(videoRecord) { (record, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error == nil {
print("upload successful")
} else {
print(error!)
}
})
}
}
Download Video
func downloadVideo(id: CKRecordID) {
privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
if error != nil {
print(" Error Fetching Record " + error!.localizedDescription)
} else {
if results != nil {
print("pulled record")
let record = results!
let videoFile = record.objectForKey("video") as! CKAsset
self.videoURL = videoFile.fileURL
print(" After Download: \(self.videoURL!)")
self.videoAsset = AVAsset(URL: self.videoURL!)
self.playVideo()
} else {
print("results Empty")
}
}
}
}
}
The root problem is that AVPlayer expects a file extension, for example .mov, but CKAsset's fileURL property points to a file that lacks an extension. The cleanest solution is to create a hard link, which avoids shuffling megabytes of data around and requires no disk space:
- (NSURL *)videoURL {
return [self createHardLinkToVideoFile];
}
- (NSURL *)createHardLinkToVideoFile {
NSError *err;
if (![self.hardURL checkResourceIsReachableAndReturnError:nil]) {
if (![[NSFileManager defaultManager] linkItemAtURL:self.asset.fileURL toURL:self.hardURL error:&err]) {
// if creating hard link failed it is still possible to create a copy of self.asset.fileURL and return the URL of the copy
}
}
return self.hardURL;
}
- (void)removeHardLinkToVideoFile {
NSError *err;
if ([self.hardURL checkResourceIsReachableAndReturnError:nil]) {
if (![[NSFileManager defaultManager] removeItemAtURL:self.hardURL error:&err]) {
}
}
}
- (NSURL *)hardURL {
return [self.asset.fileURL URLByAppendingPathExtension:#"mov"];
}
Then in the view controller, point AVPlayer to videoURL instead of asset.fileURL.
Solution ended up being that I forgot to specify the filename before I wrote the data to it. I was using URLByAppendingPathExtension and it messed up the URL, ended up using URLByAppendingPathComponent and adding a filename there. Here's the solution that worked for me! Thanks for the comments guys.
func downloadVideo(id: CKRecordID) {
privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
if error != nil {
print(" Error Fetching Record " + error!.localizedDescription)
} else {
if results != nil {
print("pulled record")
let record = results as CKRecord!
let videoFile = record.objectForKey("video") as! CKAsset
self.videoURL = videoFile.fileURL as NSURL!
let videoData = NSData(contentsOfURL: self.videoURL!)
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let destinationPath = NSURL(fileURLWithPath: documentsPath).URLByAppendingPathComponent("filename.mov", isDirectory: false) //This is where I messed up.
NSFileManager.defaultManager().createFileAtPath(destinationPath.path!, contents:videoData, attributes:nil)
self.videoURL = destinationPath
self.videoAsset = AVURLAsset(URL: self.videoURL!)
self.playVideo()
} else {
print("results Empty")
}
}
}
}
}
Here's the solution for multiple video download from CloudKit. Using this you can store the video on multiple destination and get easily file path
import AVKit
import CloudKit
var assetForVideo = [CKAsset]()
var videoURLForGetVideo = NSURL()
database.perform(queryForVideo, inZoneWith: nil) { [weak self] record, Error in
guard let records = record, Error == nil else {
return
}
DispatchQueue.main.async { [self] in
self?.assetForVideo = records.compactMap({ $0.value(forKey: "video") as? CKAsset })
for (i,dt) in self!.assetForVideo.enumerated(){
self!.videoURLForGetVideo = (dt.fileURL as NSURL?)!
let videoData = NSData(contentsOf: self!.videoURLForGetVideo as URL)
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let destinationPath = NSURL(fileURLWithPath: documentsPath).appendingPathComponent(self!.assetForVideo.count == i ? "filename\(self!.assetForVideo.count).mov" : "filename\(i+1).mov", isDirectory: false)! as NSURL
FileManager.default.createFile(atPath: destinationPath.path!, contents: videoData as Data?, attributes: nil)
self?.videoURLForGetVideo = destinationPath
self!.videoAssett = AVURLAsset(url: self!.videoURLForGetVideo as URL)
let abc = self!.videoAssett.url
let videoURL = URL(string: "\(abc)")
}
}
}
What I am trying to do is, in app delegate, I want to write a code that will copy a sqlite database if it is not exists in iphone's document directory. For that I am using the following code-
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.mainScreen().bounds)
let containerViewController = ContainerViewController()
window!.rootViewController = containerViewController
window!.makeKeyAndVisible()
//Create database if not exists
let docsPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
let databaseStr = "LocalDatabase.sqlite"
let dbPath = docsPath.stringByAppendingPathComponent(databaseStr)
let fileManager: NSFileManager = NSFileManager.defaultManager()
if !fileManager.fileExistsAtPath(dbPath) {
let databaseInApp: String? = NSBundle.mainBundle().resourcePath?.stringByAppendingPathComponent(databaseStr)
fileManager.copyItemAtPath(databaseInApp!, toPath: dbPath, error: nil)
}
return true
}
It's creating the database in the directory that is ok. But I am not getting ant tables there in database. That means new file is created instead of copying. I am sure there are 9 tables in that database which I want to copy.
Structure of files are as given in the screenshot-
Where I am wrong that I did not understand. Please tell me if anybody is able to catch the problem. One more thing When I was running the application in the simulator with the
/Users/Adelantelabs/Documents/Sidemenu.swift/SlideOutNavigation/Localdatabase.sqlite
Then it was working perfectly but did not work in iphone when I run it.
Use this code:
let fileManager = NSFileManager.defaultManager()
var error : NSError?
var doumentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
let destinationPath = doumentDirectoryPath.stringByAppendingPathComponent("LocalDatabase1.sqlite")
let sourcePath = NSBundle.mainBundle().pathForResource("LocalDatabase", ofType: "sqlite")
fileManager.copyItemAtPath(sourcePath!, toPath: destinationPath, error: &error)
func copyDatabase(){
let fileManager = NSFileManager.defaultManager()
let dbPath = getDBPath()
var success = fileManager.fileExistsAtPath(dbPath)
if(!success) {
if let defaultDBPath = NSBundle.mainBundle().pathForResource("LocalDatabase", ofType: "sqlite"){
var error:NSError?
success = fileManager.copyItemAtPath(defaultDBPath, toPath: dbPath, error: &error)
println(defaultDBPath)
if (!success){
println("Failed to create writable database file with message\(error!.localizedDescription))")
}
}else{
println("Cannot Find File In NSBundle")
}
}else{
println("File Already Exist At:\(dbPath)")
}
}
func getDBPath()->String
{
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentsDir = paths[0] as! String
let databasePath = documentsDir.stringByAppendingPathComponent("LocalDatabase.sqlite")
return databasePath;
}
Then call it in didFinishLaunching:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
copyDatabase()
return true
}
Swift 3.0 version
let fileManager = FileManager.default
var doumentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let destinationPath = doumentDirectoryPath.appendingPathComponent("LocalDatabase.sqlite")
let sourcePath = Bundle.main.path(forResource: "LocalDatabase", ofType: "sqlite")
do{
try fileManager.copyItem(atPath: sourcePath!, toPath: destinationPath)
}catch let error as NSError {
print("error occurred, here are the details:\n \(error)")
}