Load XML file from main Bundle in Swift 3.0 - swift

I have a .GPX file contains routing info of a hiking trip which I want to load into my app. Everything is ok if I load it from remote URL (https://dl.dropboxusercontent.com/u/45741304/appsettings/Phu_si_Lung_05_01_14.gpx) but I can't load this same file from app bundle (already in "Copy bundle resources" and had correct target membership).
Here's my code for loading this file from remote URL:
var xmlParser: XMLParser!
func startParsingFileFromURL(urlString: String) {
guard let url = URL(string: urlString) else {
print("Can't load URL: \(urlString)")
return
}
self.xmlParser = XMLParser(contentsOf: url)
self.xmlParser.delegate = self
let result = self.xmlParser.parse()
print("parse from URL result: \(result)")
if result == false {
print(xmlParser.parserError?.localizedDescription)
}
}
and from the main bundle:
func startParsingFile(fileName: String, fileType: String) {
guard let urlPath = Bundle.main.path(forResource: fileName, ofType: fileType) else {
print("Can't load file \(fileName).\(fileType)")
return
}
guard let url:URL = URL(string: urlPath) else {
print("Error on create URL to read file")
return
}
self.xmlParser = XMLParser(contentsOf: url)
self.xmlParser.delegate = self
let result = self.xmlParser.parse()
print("parse from file result: \(result)")
if result == false {
print(xmlParser.parserError?.localizedDescription)
}
}
Error on load from app bundle:
parse from file result: false
Optional("The operation couldn’t be completed. (Cocoa error -1.)")

You are saying:
guard let urlPath = Bundle.main.path(forResource: fileName, ofType: fileType) else {
print("Can't load file \(fileName).\(fileType)")
return
}
guard let url:URL = URL(string: urlPath) else {
print("Error on create URL to read file")
return
}
First, it is very silly to turn a string path into a URL. You knew you wanted a URL, so why didn't you start by calling url(forResource:...)?
Second, if you ever do turn a string path into a URL, you must make a file URL.

Related

Cannot write Data to file in Swift

I have an image that I want it's data to be saved in this fileUri generated by ("react-native-fs"). LibraryDirectoryPath/saved_images/{filename}:
/Users/macbookpro/Library/Developer/CoreSimulator/Devices/9CBD2F1E-7330-418D-81BE-108C064DEA7E/data/Containers/Data/Application/C26348CC-3463-43EF-9B26-B7E31641E2EA/Library/saved_images/6B3A6A3A-8DE3-488B-AF43-A54775545B38.jpg
And below is my implementation:
do {
let url = URL(string: fileUri)
let fileExisted = FileManager().fileExists(atPath: url!.path)
if (fileExisted) {
try decryptedData.write(to: url!)
} else {
let handle = try FileHandle(forWritingTo: url!)
handle.write(data) // data is type Data
handle.closeFile()
}
} catch {
reject("FileError", "Failed to write file", error)
}
I also tried let url = URL(fileURLWithPath: fileUri) with and without file:// prepending to fileUri
do {
let url = URL(fileURLWithPath: fileUri)
let fileExisted = FileManager().fileExists(atPath: url.path)
if (fileExisted) {
try decryptedData.write(to: url)
} else {
let handle = try FileHandle(forWritingTo: url)
handle.write(data)
handle.closeFile()
}
} catch {
reject("FileError", "Failed to write file " + error.localizedDescription, error)
}
it says:
You are using the wrong API.
let url = URL(string: fileUri)
is for strings representing a full – even encoded - URL starting with a scheme like file:// or https://.
On the other hand fileUri is actually a path without a scheme, so you have to use
let url = URL(fileURLWithPath: fileUri)
This returns a non optional URL by adding the file:// scheme.
fileUri should be renamed as filePath.

View pdf documents

I have a table with the names of pdf documents. Previously, there were 3 documents and each one has its own ViewController. How can I make it so that with hundreds of documents, I would select one from the table and show it on the View, if I select another document, then on the same View show another document.
while I have such a function, where I substituted the name of the documents in each class and showed it in different representations. But now I need to display everything on one ViewController when selecting any document
import UIKit
import PDFKit
class pdfViewClass {
class func filePDfFunc(nameFile: String, formatFile:String,
nameView:PDFView)
{
if let path = Bundle.main.path(forResource: nameFile,
ofType:formatFile) {
if let pdfDocument = PDFDocument(url: URL(fileURLWithPath:
path)) {
nameView.autoScales = true
nameView.displayDirection = .vertical
nameView.document = pdfDocument
}
}
}
}
You can use Native Apple UIDocumentInteractionController for viewing PDF file.
Create a function like below for View PDF
func viewPdf(urlPath: String, screenTitle: String) {
// open pdf for booking id
guard let url = urlPath.toUrl else {
print("Please pass valid url")
return
}
self.downloadPdf(fileURL: url, screenTitle: screenTitle) { localPdf in
if let url = localPdf {
DispatchQueue.main.sync {
self.openDocument(atURL: url, screenTitle: screenTitle)
}
}
}
}
Function for download PDF
// method for download pdf file
func downloadPdf(fileURL: URL, screenTitle: String, complition: #escaping ((URL?) -> Void)) {
// Create destination URL
if let documentsUrl: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let destinationFileUrl = documentsUrl.appendingPathComponent("\(screenTitle).pdf")
if FileManager.default.fileExists(atPath: destinationFileUrl.path) {
try? FileManager.default.removeItem(at: destinationFileUrl)
}
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)
complition(destinationFileUrl)
} catch let writeError {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
} else {
print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "N/A")")
}
}
task.resume()
} else {
complition(nil)
}
}
Function for open documents
func openDocument(atURL url: URL, screenTitle: String) {
self.documentInteractionController.url = url
self.documentInteractionController.name = screenTitle
self.documentInteractionController.delegate = self
self.documentInteractionController.presentPreview(animated: true)
}
On tap of tableView pass the specific index URL
viewPdf(urlPath: "http://www.africau.edu/images/default/sample.pdf", screenTitle: "Tesing Document")
You can do it using WKWebView easily. Use WKWebView to load your pdf doc.

unzip downloaded zip file using SSZipArchive

the code i used for downloading the book is ..
//Create URL to the source file you want to download
let fileURL = URL(string:myFileURL)
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)")
DispatchQueue.main.async {
self.toast(msg: "Download completed")
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
}
}
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);
}
after that i tried to unzip the epub file from the destinationFileUrl using the code
let status = SSZipArchive.unzipFile(atPath: destinationFileUrl , toDestination:destPath, delegate:self)
the status value returns false, so the output folder only contains META-INF folder with no items
How can i unzip the epub correctly
Please refer this -->> Not getting eject file after unzipping downloaded file URL
var filepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
filepath += "/\(UUID().uuidString)"
let url = URL(fileURLWithPath: filepath)
do {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
let done = SSZipArchive.unzipFile(atPath: path!, toDestination: url.path)
if done{
let items = try FileManager.default.contentsOfDirectory(atPath: url.path)
print(items)
}
} catch let error as NSError{
print(error)
}

How do I save an image to a png file?

How do I load an image from specified url and save it to an existing local png file ? I'm trying to do it as follow but get an error
The file couldn’t be saved because the specified URL type isn’t supported
let url = URL(string: urlString)
let data = try? Data(contentsOf: url!)
try data?.write(to: URL(string: "icon.png")!)
First of all never use synchronous Data(contentsOf to load data from a server.
The error occurs because the URL has the wrong format
A remote URL must contain a scheme and host (http://server.com...)
An local URL in the file system must be created with URL(fileURLWithPath: and the path must start with a slash.
Use the following code to asynchronously download a file:
extension FileManager {
open func secureCopyItem(at srcURL: URL, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) {
try FileManager.default.removeItem(at: dstURL)
}
try FileManager.default.copyItem(at: srcURL, to: dstURL)
} catch (let error) {
print("Cannot copy item at \(srcURL) to \(dstURL): \(error)")
return false
}
return true
}
}
func download() {
let storagePathUrl = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("file.png")
let fileUrl = "https://server/file.png"
let urlRequest = URLRequest(url: URL(string: fileUrl)!)
let task = URLSession.shared.downloadTask(with: urlRequest) { tempLocalUrl, response, error in
guard error == nil, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
print("Error")
return
}
guard FileManager.default.secureCopyItem(at: tempLocalUrl!, to: storagePathUrl) else {
print("Error")
return
}
}
task.resume()
}

Error copying files with FileManager (CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme)

I'm trying to copy some (media) files from one folder to another using FileManager's copyItem(at:path:), but I'm getting the error:
CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
Error Domain=NSCocoaErrorDomain Code=262 "The file couldn’t be opened because the specified URL type isn’t supported."
I'm using Xcode 9 beta and Swift 4.
let fileManager = FileManager.default
let allowedMediaFiles = ["mp4", "avi"]
func isMediaFile(_ file: URL) -> Bool {
return allowedMediaFiles.contains(file.pathExtension)
}
func getMediaFiles(from folder: URL) -> [URL] {
guard let enumerator = fileManager.enumerator(at: folder, includingPropertiesForKeys: []) else { return [] }
return enumerator.allObjects
.flatMap {$0 as? URL}
.filter { $0.lastPathComponent.first != "." && isMediaFile($0)
}
}
func move(files: [URL], to location: URL) {
do {
for fileURL in files {
try fileManager.copyItem(at: fileURL, to: location)
}
} catch (let error) {
print(error)
}
}
let mediaFilesURL = URL(string: "/Users/xxx/Desktop/Media/")!
let moveToFolder = URL(string: "/Users/xxx/Desktop/NewFolder/")!
let mediaFiles = getMediaFiles(from: mediaFilesURL)
move(files: mediaFiles, to: moveToFolder)
The error occurs because
URL(string: "/Users/xxx/Desktop/Media/")!
creates a URL without a scheme. You can use
URL(string: "file:///Users/xxx/Desktop/Media/")!
or, more simply,
URL(fileURLWithPath: "/Users/xxx/Desktop/Media/")
Note also that in fileManager.copyItem() the destination must
include the file name, and not only the destination
directory:
try fileManager.copyItem(at: fileURL,
to: location.appendingPathComponent(fileURL.lastPathComponent))