I have got the URL of a file using file importer. Now I want to store the file in a variable so that I can send it to the server.
.fileImporter(isPresented: $openfile, allowedContentTypes: [.audio,.pdf,.png, .text, .jpeg], allowsMultipleSelection: false) { (res) in
do{
let fileURL = try res.get()
//getting file name
self.fileName = fileURL.last?.lastPathComponent ?? "File Uplaoded"
print(fileURL)
}catch{
print("Error reading docs")
print(error.localizedDescription)
}
}
How can I save the file in a variable from the fileURL?
The stackoverflow answer shows you how to go about getting the file content.
You have to adapt the answer to your code, something like:
var fileData: Data?
.fileImporter(isPresented: $openfile, allowedContentTypes: [.audio,.pdf,.png, .text, .jpeg], allowsMultipleSelection: false) { (res) in
do{
let fileURL = try res.get()
if let url = fileURL.first {
fileName = url.lastPathComponent
fileData = try Data(contentsOf: url)
print("\n fileName: \(fileName) \n url: \(url) \n fileData: \(fileData)")
}
}catch{
print("Error reading docs")
print(error.localizedDescription)
}
}
Then you can use fileData to send to the server.
Related
I've read lots of SO question on it, but they are not applying in my case.
I follow the steps mentioned in Parse JSON from file and URL with Swift, project structure is:
The code:
import Foundation
struct DemoData: Codable {
let title: String
let description: String
}
func readLocalFile(forName name: String) -> Data? {
do {
if let bundlePath = Bundle.main.path(forResource: name,
ofType: "json"),
let jsonData = try String(contentsOfFile: bundlePath).data(using: .utf8) {
return jsonData
}
} catch {
print(error)
}
return nil
}
func parse(jsonData: Data) {
do {
let decodedData = try JSONDecoder().decode(DemoData.self,
from: jsonData)
print("Title: ", decodedData.title)
print("Description: ", decodedData.description)
print("===================================")
} catch {
print("decode error")
}
}
if let localData = readLocalFile(forName: "data") {
print("running")
parse(jsonData: localData)
} else {
print("final nil")
}
And it turn out to be:
final nil
Program ended with exit code: 0
PS: Config of the json data
You are suppressing some potential errors, I recommend this (generic) version, it throws all possible errors
enum ReadError : Error { case fileIsMissing }
func readLocalFile<T : Decodable>(forName name: String) throws -> T {
guard let url = Bundle.main.url(forResource: name,
withExtension: "json") else {
throw ReadError.fileIsMissing
}
let jsonData = try Data(contentsOf: url)
return try JSONDecoder().decode(T.self, from: jsonData)
}
do {
let localData : DemoData = try readLocalFile(forName: "data")
print("===================================")
print("running")
print("Title: ", localData.title)
print("Description: ", localData.description)
print("===================================")
} catch {
print("An error occured", error)
}
Edit:
Your code doesn't work because your target is a command line tool.
CLIs don't have a bundle therefore there is no Resources folder either.
The problem might be with the text encoding format of the json file. Please check and it should be Unicode (UTF-8) since you're using text encoding format as .utf8 in readLocalFile file method.
This function makes a request to a SOAP API, and then uses the response to build a view. I would like to cache this response for offline usage.
func getUserFilesWithUserObj(userObj:User,completionhandler:#escaping (_ userFiles:NSArray, _ status: Bool) -> Void){
let soapMessage: String = String(format: "<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"><soap12:Body><getFilesByID xmlns=\"http://example.com/\"><_usrID>%#</_usrID><_utStatus>%#</_utStatus></getFilesByID></soap12:Body></soap12:Envelope>",userObj.userId!,"9")
guard let urlRequest = self.createSoapRequestFromSoapMessage(soapmessage: soapMessage) else{
return
}
var localPath = AppDelegate.getDownloadFilesFolderPath()
localPath = localPath.stringByAppendingPathComponent(path: "user-files")
if FileManager.default.fileExists(atPath: localPath){
do {
self.processUserFiles(files: try String(contentsOf: NSURL(fileURLWithPath: localPath) as URL, encoding: .utf8))
} catch let error as NSError { print(error) }
}
else{
SwiftLoader.show(animated: true)
Alamofire.request(urlRequest).responseData { (response) in
SwiftLoader.hide()
if response.error == nil{
if response.data != nil{
let strData = String(data: response.data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))
do {
try strData?.write(to: NSURL(string: localPath)! as URL, atomically: false, encoding: .utf8)
} catch let error as NSError { print(error) }
self.processUserFiles(files: strData!)
completionhandler(self.arrUserTreatment!, true)
}
completionhandler(NSArray(), false)
}
else{
completionhandler(NSArray(), false)
}
}
}
}
Here is the error message I am receiving in the Xcode terminal,
2019-08-19 21:51:57.131031-0400 AppName[412:28510] CFURLCopyResourcePropertyForKey failed because it was passed an URL which has no scheme
Error Domain=NSCocoaErrorDomain Code=518 "The file couldn’t be saved because the specified URL type isn’t supported." UserInfo={NSURL=/var/mobile/Containers/Data/Application/AFFBB2E6-0EB9-4206-9AD5-EDB3AD22A23F/Documents/DownloadFiles/user-files}
How can I save the XML from this response to a file and reload it later?
Prepending file:// to the localPath fixed the error.
var localPath = AppDelegate.getDownloadFilesFolderPath()
localPath = "file://" + localPath.stringByAppendingPathComponent(path: "user-files")
Source: https://stackoverflow.com/a/39646856/8507637
First of all, after successfully download from the URL using Alamofire, I am changing the file extension to.ZIP, then getting an error while unzipping.
Not getting expected file.
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
Alamofire.download(fileURL!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers, to: destination).downloadProgress(closure: { (progress) in
print(progress.completedUnitCount)
}).responseData { (responce) in
let destiUrl = responce.destinationURL
print(destiUrl!)
let newUrl = destiUrl?.deletingPathExtension().appendingPathExtension("zip")
do {
try FileManager.default.copyItem(at: destiUrl!, to: newUrl!)
let unzipDirectory = try Zip.quickUnzipFile(newUrl!)
print(unzipDirectory.absoluteString)
}
catch let error as NSError{
print(error)
}
}
File URL after successful download-->
file:///var/mobile/Containers/Data/Application/9D96958C-903E-4693-9965-6FB919BB24F1/Documents/'87dc4a8ddce24cf9ad35a251d6a98195.hub'
File URL after converting to .zip
file:///var/mobile/Containers/Data/Application/9D96958C-903E-4693-9965-6FB919BB24F1/Documents/'87dc4a8ddce24cf9ad35a251d6a98195.zip
Final url after unzipping
file:///var/mobile/Containers/Data/Application/9D96958C-903E-4693-9965-6FB919BB24F1/Documents/'87dc4a8ddce24cf9ad35a251d6a98195/
Actual result should be audio file.
Tried replacing the name of the file at the time of successfully download using below code. -->
func saveFileInDocDirectory(data: Data?, fileName: String?, successblock: #escaping (_ path: String?) -> Void) { // To add the image to cache for given identifier.
let paths = NSSearchPathForDirectoriesInDomains( .documentDirectory, .userDomainMask, true)[0] as String
let path = paths.appending("/\(fileName!)")
if (FileManager.default.fileExists(atPath: path)) {
try! FileManager.default.removeItem(atPath: path)
} else {
do {
try data?.write(to: URL(fileURLWithPath: path, isDirectory: false))
successblock(path)
} catch {
successblock(nil)
print("Error while caching the data in cache folder.")
}
}
}
And after that unzipped using SSZipArchive library in Alamofire download function -->
Alamofire.download(fileURL!, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: headers, to: destination).downloadProgress(closure: { (progress) in
print(progress.completedUnitCount)
}).responseData { (responce) in
let destiUrl = responce.destinationURL
print(destiUrl!)
let name = destiUrl?.deletingPathExtension().lastPathComponent
self.saveFileInDocDirectory(data: responce.result.value, fileName: "\(name!).zip", successblock: { (path) in
print(path!)
var filepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true)[0]
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)
let destinationUrl = url.appendingPathComponent(items[0])
print(destinationUrl)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
player = AVQueuePlayer(url: destinationUrl)
player.play()
}
} catch let error as NSError{
print(error)
}
})
}
I created a small app that creates a CSV file and now I want to upload it to a dropbox folder.
Problem Schema
import SwiftyDropbox
class ViewController: UIViewController {
func myButtonInControllerPressed() {
DropboxClientsManager.authorizeFromController(UIApplication.shared,
controller: self,
openURL: { (url: URL) -> Void in
UIApplication.shared.openURL(url)
})
}
let client = DropboxClientsManager.authorizedClient
let fileData = "teste.csv".data(using: String.Encoding.utf8, allowLossyConversion: false)!
client?.files.upload(path: "/test/path/in/Dropbox/account/HealthkitFromTheGround", input: fileData)
.response { response, error in
if let response = response {
print(response)
} else if let error = error {
print(error)
}
}
.progress { progressData in
print(progressData)
}
let fileName = "teste.csv"
let tempDir = NSTemporaryDirectory()
let fileURL = URL(fileURLWithPath: tempDir, isDirectory: true).appendingPathComponent(fileName)
do {
try csvString.write(to: fileURL, atomically: true, encoding: .utf8)
print("Created file")
} catch {
print("Failed to create file: \(error)")
return
}
What should I do to write directly to the app dropbox folder?
Thanks!
This is what I use for uploading TCX files (it's basically the same as your csv file as it's also text based) into a folder in Dropbox (I'm using saver) scope
static func dropboxSync() {
let client = DropboxClientsManager.authorizedClient
let latestTCXpath = TCXfuncs.listTCX()[0]
let fullPathName = "/" + latestTCXpath.lastPathComponent
let fileData = try! Data(contentsOf: latestTCXpath)
_ = client?.files.upload(path: fullPathName, input: fileData)
.response { response, error in
if let response = response {
print(response)
} else if let error = error {
print(error)
}
}
// .progress { progressData in
// print(progressData)
}
note:
These are the 2 items which I got stumped based on the official docs from SwiftyDropbox on GitHub.
fullPathName is "/" + "workout.tcx" (file gets uploaded to my dropbox within the Apps directory under the directory where I specify in App Console). Hence, the workout.tcx file would get written to
-- dropbox
-- Apps
-- Breakaway
-- workout.tcx
latestTCXpath is the full pathname to where the workout.tcx is stored within the iOS app's document directory. Example in the simulator:
file:///Users/testUser/Library/Developer/CoreSimulator/Devices/B4759D88-DFB6-43C0-A6E9-84FE3F23B9A0/data/Containers/Data/Application/8C348B27-FB2E-42E2-8425-92844DF18596/Documents/workout.tcx
I download a zip file with Alamofire4 and unzip it with SSZipArchive but the unzip does not work. I am not sure if the path of the downloaded file is good with Alamofire.
Here is the code:
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return (documentsURL, [.removePreviousFile])
}
Alamofire.download(urlString, method: .get, parameters: parameters, encoding: JSONEncoding.default, to: destination)
.response{ response in
if response.error == nil {
let filename = response.response?.suggestedFilename
var folderDestination=response.destinationURL?.path
folderDestination=folderDestination?.appending("/\(nameCategory)")
archiveToUnzip=(folderDestination?.appending("/\(filename!)"))!
//unzip
let successUnZip=SSZipArchive.unzipFile(atPath: archiveToUnzip, toDestination:folderDestination!)
if !successUnZip {
SpeedLog.print("Problem unzip")
}
}
}
It displays "Problem unzip", so am I wrong in the path to the zip file?
Before unzipping try to check that all paths were correct:
guard let zipPath = (folderDestination?.appending("/\(filename!)"))! else {
print("Error: zipPath are not correct: \(zipPath)")
return
}
guard let unzipPath = folderDestination! else {
print("Error: unzipPath are not correct: \(unzipPath)")
return
}
let success = SSZipArchive.unzipFile(atPath: zipPath, toDestination: unzipPath)
if !success {
print("Error: unzipFile operation failed")
return
}
Simply you can't create folder name by appending the path, You need to create folder separately. Here is the code try this!
let filename = response.response?.suggestedFilename
var folderDestination=response.destinationURL?.path
folderDestination=folderDestination?.appending("/\(nameCategory)")
try! FileManager.default.createDirectory(at: folderDestination!, withIntermediateDirectories: false, attributes: nil)
archiveToUnzip=(folderDestination?.appending("/\(filename!)"))!
//unzip
let successUnZip=SSZipArchive.unzipFile(atPath: archiveToUnzip,toDestination:folderDestination!)