Load GIF from documents directory and convert it to data - swift

guard let imageData = try? Data(contentsOf: bundleURL) else {
print("Cannot turn image named \"\(gifNamed)\" into NSData")
return nil
}
I want to use GIF path in documents directory and extract the data from it not with bundleUrl but with GIF path in : file:///var/mobile/Containers/Data/Application/5615E8E1-F120-4171-A7CE-B2A9F2E8FC19/Documents/test.gif

If I understand correctly you want to get data from gif that is located in you app's Documents directory. Your code may look like that:
func getDataOf(gifNamed: String) -> Data? {
// Get url of Documents directory
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
guard let documentsDirectory = paths.first else { return nil }
// Get url of your gif
guard let gifURL = documentsDirectory.appendingPathComponent(gifNamed) else { return nil }
// Extract the data of your gif
var data: Data?
do {
data = try Data(contentsOf: bundleURL)
} catch {
print(error)
}
return data
}

Related

Save archive unarchived SCNNode any specific format?

I'm try to archive and unarchived an SCNnode with the following code.
func writeData(nodoToSaved: SCNNode) {
let fixedFilename = String("terrainSaved") // just a reference Name
let fullPath = getDocumentsDirectory().appendingPathComponent(fixedFilename)
do {
guard let data = try? NSKeyedArchiver.archivedData(withRootObject: nodoToSaved, requiringSecureCoding: false)
else { fatalError("can't encode data") }
try data.write(to: fullPath)
print("Saved Successufully")
print("Full Path for write is: \(fullPath)")
} catch {
print("Couldn't write file")
}
}
// Read Data Function
func readData() {
let fixedFilename = String("terrainSaved")
let fullPath = getDocumentsDirectory().appendingPathComponent(fixedFilename)
print("Full Path for Read is: \(fullPath)")
guard let data = try? Data(contentsOf: fullPath) else {
print("no data found")
return }
do {
guard let terreno = try NSKeyedUnarchiver.unarchivedObject(ofClass: SCNNode.self, from: data) else
{return}
self.rootNode.addChildNode(terreno)
} catch let err{
print("error can't decode the saved data \(err.localizedDescription)")
}
}
// Helper Function
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
I'm able to save the file at path , but when I try to read I'm getting the following error:
error can't decode the saved data The data couldn’t be read because it isn’t in the correct format
Is there any specific format I should use after my name file? "terrainSaved.scn" ..
Thanks in advance.

How to save images in ascending order in swift?

I am building an application in which i am using FileManager to save some images using device camera. So for Now I am saving file name as Doc-Time.
I am using below code,
func saveImageToDocumentDirectory(image: UIImage ) {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm:ss"
let fileName = "Doc-" + dateFormatter.string(from: Date())
let fileURL = documentsDirectory.appendingPathComponent(fileName
)
if let data = image.jpegData(compressionQuality: 1.0),!FileManager.default.fileExists(atPath: fileURL.path){
do {
try data.write(to: fileURL)
print("file saved")
} catch {
print("error saving file:", error)
}
}
}
But Here i want to as, Doc-1,Doc-2, Doc-3....
How can i do that?
You can achieve this by simply storing the next index of the image. Like first the index should be 1 when you used named the image as Doc-1 then the index has 2 in it and so on....
One way to store this index in UserDefaults like:
var nextImageIndex: Int {
UserDefaults.standard.integer(forKey: "NextImageIndex") + 1 //+1 if you want to start with 1
}
func incrementImageIndex() {
UserDefaults.standard.setValue(nextImageIndex, forKey: "NextImageIndex")
}
Put the above code somewhere in UIViewController to see it works.
Here is your updated method...
func saveImageToDocumentDirectory(image: UIImage ) {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return
}
let fileName = "Doc-\(nextImageIndex)"
let fileURL = documentsDirectory.appendingPathComponent(fileName)
let fileAlreadyExists = FileManager.default.fileExists(atPath: fileURL.path)
if let data = image.jpegData(compressionQuality: 1.0), !fileAlreadyExists {
do {
try data.write(to: fileURL)
incrementImageIndex()
print("file saved")
} catch {
print("error saving file:", error)
}
}
}
Create a variable to store the document count and increment it every time your save to the document directory, then use that value in the string.
let documentKey = "documentIndex"
#objc var documentIndex: Int {
get { UserDefaults.value(forKey: documentKey) as? Int ?? 0 }
set { UserDefaults.setValue(newValue, forKey: documentKey) }
}
func saveImageToDocumentDirectory(image: UIImage ) {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
documentIndex += 1
let fileName = "Doc-\(documentIndex)"
let fileURL = documentsDirectory.appendingPathComponent(fileName
)
if let data = image.jpegData(compressionQuality: 1.0),!FileManager.default.fileExists(atPath: fileURL.path){
do {
try data.write(to: fileURL)
print("file saved")
} catch {
print("error saving file:", error)
}
}
}

How do I solve the strange "filehandle" problem? [duplicate]

I know there are a few questions pertaining to this, but they're in Objective-C.
How can I access a .txt file included in my app using Swift on an actual iPhone? I want to be able to read and write from it. Here are my project files if you want to take a look. I'm happy to add details if necessary.
Simply by searching in the app bundle for the resource
var filePath = NSBundle.mainBundle().URLForResource("file", withExtension: "txt")
However you can't write to it because it is in the app resources directory and you have to create it in the document directory to write to it
var documentsDirectory: NSURL?
var fileURL: NSURL?
documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last!
fileURL = documentsDirectory!.URLByAppendingPathComponent("file.txt")
if (fileURL!.checkResourceIsReachableAndReturnError(nil)) {
print("file exist")
}else{
print("file doesnt exist")
NSData().writeToURL(fileURL!,atomically:true)
}
now you can access it from fileURL
EDIT - 28 August 2018
This is how to do it in Swift 4.2
var filePath = Bundle.main.url(forResource: "file", withExtension: "txt")
To create it in the document directory
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
let fileURL = documentsDirectory.appendingPathComponent("file.txt")
do {
if try fileURL.checkResourceIsReachable() {
print("file exist")
} else {
print("file doesnt exist")
do {
try Data().write(to: fileURL)
} catch {
print("an error happened while creating the file")
}
}
} catch {
print("an error happened while checking for the file")
}
}
Swift 3, based on Karim’s answer.
Reading
You can read files included in an app’s bundle through the bundle’s resource:
let fileURL = Bundle.main.url(forResource:"filename", withExtension: "txt")
Writing
However, you can’t write there. You will need to create a copy, preferably in the Documents directory:
func makeWritableCopy(named destFileName: String, ofResourceFile originalFileName: String) throws -> URL {
// Get Documents directory in app bundle
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
fatalError("No document directory found in application bundle.")
}
// Get URL for dest file (in Documents directory)
let writableFileURL = documentsDirectory.appendingPathComponent(destFileName)
// If dest file doesn’t exist yet
if (try? writableFileURL.checkResourceIsReachable()) == nil {
// Get original (unwritable) file’s URL
guard let originalFileURL = Bundle.main.url(forResource: originalFileName, withExtension: nil) else {
fatalError("Cannot find original file “\(originalFileName)” in application bundle’s resources.")
}
// Get original file’s contents
let originalContents = try Data(contentsOf: originalFileURL)
// Write original file’s contents to dest file
try originalContents.write(to: writableFileURL, options: .atomic)
print("Made a writable copy of file “\(originalFileName)” in “\(documentsDirectory)\\\(destFileName)”.")
} else { // Dest file already exists
// Print dest file contents
let contents = try String(contentsOf: writableFileURL, encoding: String.Encoding.utf8)
print("File “\(destFileName)” already exists in “\(documentsDirectory)”.\nContents:\n\(contents)")
}
// Return dest file URL
return writableFileURL
}
Example usage:
let stuffFileURL = try makeWritableCopy(named: "Stuff.txt", ofResourceFile: "Stuff.txt")
try "New contents".write(to: stuffFileURL, atomically: true, encoding: String.Encoding.utf8)
Just a quick update for using this code with Swift 4:
Bundle.main.url(forResource:"YourFile", withExtension: "FileExtension")
And the following has been updated to account for writing the file out:
var myData: Data!
func checkFile() {
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
let fileURL = documentsDirectory.appendingPathComponent("YourFile.extension")
do {
let fileExists = try fileURL.checkResourceIsReachable()
if fileExists {
print("File exists")
} else {
print("File does not exist, create it")
writeFile(fileURL: fileURL)
}
} catch {
print(error.localizedDescription)
}
}
}
func writeFile(fileURL: URL) {
do {
try myData.write(to: fileURL)
} catch {
print(error.localizedDescription)
}
}
This particular example is not the most flexible, but with a little bit of work you can easily pass in your own file names, extensions and data values.
🎁 Property Wrapper - Fetch and convert to correct data type
This simple wrapper helps you to load any file from any bundle in a cleanest way:
#propertyWrapper struct BundleFile<DataType> {
let name: String
let type: String
let fileManager: FileManager = .default
let bundle: Bundle = .main
let decoder: (Data) -> DataType
var wrappedValue: DataType {
guard let path = bundle.path(forResource: name, ofType: type) else { fatalError("Resource not found: \(name).\(type)") }
guard let data = fileManager.contents(atPath: path) else { fatalError("Can not load file at: \(path)") }
return decoder(data)
}
}
Usage:
#BundleFile(name: "avatar", type: "jpg", decoder: { UIImage(data: $0)! } )
var avatar: UIImage
You can define any decoder to match your needs
Get File From Bundle in Swift 5.1
//For Video File
let stringPath = Bundle.main.path(forResource: "(Your video file name)", ofType: "mov")
let urlVideo = Bundle.main.url(forResource: "Your video file name", withExtension: "mov")
Bundles are read only. You can use NSBundle.mainBundle().pathForResource to access the file as read-only, but for read-write access you need to copy your document to Documents folder or tmp folder.
Bundles can be written. You can use Bundle.main.path to overwrite file by adding it into Copy Bundles Resource.
I have to use a file from another bundle. So, following code worked for me. Needful when you work with a frameworks.
let bundle = Bundle(for: ViewController.self)
let fileName = bundle.path(forResource: "fileName", ofType: "json")

How to first download audio files from URLs and then play all

I have got multiple audio files on server.
I want to download all audio files first, and then when all are downloaded, i need to play them one after another.
What will be the best approach to achieve this?
Thanks!
if let audioUrl = URL(string: "http://freetone.org/ring/stan/iPhone_5-Alarm.mp3") {
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
print(destinationUrl)
// to check if it exists before downloading it
if FileManager.default.fileExists(atPath: destinationUrl.path) {
print("The file already exists at path")
// if the file doesn't exist
} else {
// you can use NSURLSession.sharedSession to download the data asynchronously
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) -> Void in
guard let location = location, error == nil else { return }
do {
// after downloading your file you need to move it to your destination url
try FileManager.default.moveItem(at: location, to: destinationUrl)
print("File moved to documents folder")
} catch let error as NSError {
print(error.localizedDescription)
}
}).resume()
}
}

Trying to clear document folder Swift

I use following method to add file (download) to document directory:
static func downloadFileWithLink(linkString : String){
// Create destination URL
let documentsUrl:URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
let destinationFileUrl = documentsUrl.appendingPathComponent("downloadedFile")
//Create URL to the source file you want to download
let fileURL = URL(string: linkString)
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
} catch (let writeError) {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
} else {
print("Error took place while downloading a file. Error description: %#", error?.localizedDescription);
}
}
task.resume()
}
It simply download file to document folder in sandbox. I looked for method that delete files in documents folder, and tried following:
static func deleteFiledInDocDirectory(){
let fileManager = FileManager.default
let tempFolderPath = NSTemporaryDirectory()
do {
let filePaths = try fileManager.contentsOfDirectory(atPath: tempFolderPath)
for filePath in filePaths {
try fileManager.removeItem(atPath: tempFolderPath + filePath)
}
} catch {
print("Could not clear temp folder: \(error)")
}
}
However, when i inspect sandbox, downloaded file is still here. How to delete it?
In deleteFiledInDocDirectory() you're using NSTemporaryDirectory instead of the documents directory that you originally saved the file to.
Change tempFolderPath to be set using following:
guard let tempFolderPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
return // documents directory not found for some reason
}
The full method:
static func deleteFiledInDocDirectory(){
guard let tempFolderPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.absoluteString else {
return // documents directory not found for some reason
}
let fileManager = FileManager.default
do {
let filePaths = try fileManager.contentsOfDirectory(atPath: tempFolderPath)
for filePath in filePaths {
try fileManager.removeItem(atPath: tempFolderPath + filePath)
}
} catch {
print("Could not clear temp folder: \(error)")
}
}