I'm trying to download a file (namely 'xp-en.zip') from a certain server. I've already checked that this file exists using contentsOfDirectory(::), but for some reason, after the download is completed the file doesn't show up in the directory it was supposed to have been copied to. I'm using XCode and I thought it could have something to do with the app's permissions (since the destination directory is .documentDirectory), but I tried changing it to the main bundle to no avail.
I also tried downloading from another server ('speedtest.tele2.net') but it didn't work either.
let credential = URLCredential(user: "anonymous", password: "123456", persistence: .permanent)
let fileManager = FileManager.default
func FTPDownloadUpload(download: Bool = true, server: String, path: String){
let localFilePath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
guard let url = URL(string: server) else{
print("Invalid URL")
return
}
let FTPProvider = FTPFileProvider(baseURL: URL(string: "ftp://" + server)!, mode: .passive, credential: credential, cache: URLCache())
if download{
FTPProvider?.copyItem(path: "/" + path, toLocalURL: localFilePath, completionHandler: {x in print("Download completed")})
//I know this completionHandler closure kinda sucks but I don't know what else to put inside it. Keep in mind my program doesn't have anything to do after calling this function
}else{
//This is the upload section. Didn't include it to keep the code shorter
}
}
My function call is:
FTPDownloadUpload(server: "176.74.128.88", path: "xp-en.zip")
Related
I'm trying to write a file locally but no success. When I try to get the user's document directory it returns nil and I believe this is why my file is not been stored.
Also, I have many doubts of what the "user's document directory" is supposed to mean. Is it the "Documents/" inside "iCloud Drive" or "on my phone". Should I be looking in another place instead of "Files" app? I'm using the iPhone simulator.
My code is designed as follow. documentFolderURL, fileURL and url are all nil when debugging.
let documentFolderURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last
let ext: String = type ?? "pdf"
let name = "extrato." + ext
let fileURL = documentFolderURL?.appendingPathComponent(name)
do {
if let url = fileURL {
try file.write(to: url, options: .atomic)
}
} catch {...}
Use the throwing API to get an error (there should be none)
do {
let documentFolderURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let ext: String = type ?? "pdf"
let fileURL = documentFolderURL.appendingPathComponent(name).appendingPathExtension(ext)
try file.write(to: fileURL, options: .atomic)
} catch { print(error) }
It seems that you are creating the file successfully, but you aren't looking for it in the right place.
You can navigate to the simulator's User Defaults folder by:
Print the file path of the simulator's documents directory. print(documentFolderURL) should print something like file:///Users/yourname/Library/Developer/CoreSimulator/Devices/8DAF542C-4B37-41D1-BA43-1D7C2A32E585/data/Containers/Data/Application/63545C94-56F5-3B11-B601-543801BE717A/Documents/
Copy the entire url EXCEPT the leading file:// (in other words, start with /User/yourname...
Open your macbook's Finder app, and press command + shift + g. This will allow you to...(drum roll please)...
Paste in the url to navigate to your simulator's documents directory.
Your file should be there :)
So the app I'm making creates a file called "logfile" and I'm trying to send that file via Alamofire upload to a server. The file path printed in the console log is
/var/mobile/Containers/Data/Application/3BE13D78-3BF0-4880-A79A-27B488ED9EFE/Documents/logfile.txt
and the file path I can use to manually access the log created in the .xcappdata is
/AppData/Documents/logfile.txt
To access it, I'm using
let fileURL = Bundle.main.url(forResource: "", withExtension: "txt")
where inbetween the double quotes for "forResource", I've tried both file paths I listed in the previous paragraph as well as just the file name but I'm getting a nil value for file found for either. The file isn't recognized to be there, presumably because the file path I'm using is wrong as Alamofire is returning nil when trying to locate send the file. Anyone know the direct file path I'm supposed to use to be able to grab my file since the other two don't supposedly work? Thank you!
Use below code to get string data from text file to upload to server:
let fileName = "logfile"
let documentDirURL = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = documentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
var readString = "" // Used to store the file contents
do {
// Read the file contents
readString = try String(contentsOf: fileURL)
} catch let error as NSError {
print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
}
print("File Text: \(readString)") // Send 'readString' to server
If you're dynamically creating the file at runtime, it won't be in your app bundle so the Bundle class won't be able to find it. The directories you see are also dynamically-generated and not only platform-specific, but also device-specific, so you can't use the file paths directly. Instead, you'll have to ask for the proper directory at runtime from the FileManager class, like this:
guard let documents = FileManager.default.urls(for: .documentsDirectory, in: .userDomainMask).first else{
// This case will likely never happen, but forcing anything in Swift is bad
return
}
let logURL = URL(string: "logfile.txt", relativeTo: documents)
do{
let fileContents = String(contentsOf: logURL)
// Send your file to your sever here
catch{
// Handle any errors you might've encountered
}
Note that I'm guessing based on the paths you pasted in your answer you put it in your application's documents directory. That's a perfectly fine place to put this type of thing, but if I'm wrong and you put it in a different place, you'll have to modify this code to point to the right place
I have an issue with saving/replacing image files to the Documents folder in my app.
In the AppDelegate I have a two properties:
let documentsDirectory: URL = { return FileManager().urls(for: .documentDirectory, in: .userDomainMask).first! }()
let defaultDirectory: URL = { return Bundle.main.bundleURL.appendingPathComponent("DefaultBlocks.bundle", isDirectory: true) }()
It looks like the path is valid, have a log output:
[Verbose] application(:didFinishLaunchingWithOptions:) > Docs URL:
file:///var/mobile/Containers/Data/Application/6ED04DA7-077F-4AE2-AB74-2EED02932823/Documents/
[Verbose] application(:didFinishLaunchingWithOptions:) > Defaults URL: file:///var/containers/Bundle/Application/A11D6A4A-E108-483F-86EC-BBFA10E77F72/TheAwesomeApp.app/DefaultBlocks.bundle/
My app logic is: if user requested to reload default images, then replace images in the Documents folder with the reference copies from the app bundle.
I try to implement replacement in the code (called from didFinishLaunchingWithOptions):
func ReloadDefaults() {
let fileManager = FileManager.default
do {
let destDirURL = appDelegate.documentsDirectory
let defaultURLs = Bundle.main.urls(forResourcesWithExtension: "png", subdirectory: "DefaultBlocks.bundle/_default_images_")
for url in defaultURLs! {
let destURL: URL = destDirURL.appendingPathComponent(url.lastPathComponent)
log.verbose("Src URL: \(url)")
log.verbose("Dest URL: \(destURL)")
_ = try fileManager.replaceItemAt(destURL, withItemAt: url.absoluteURL)
}
}
catch {
log.error("File copy error: \(error.localizedDescription)")
}
}
[Verbose] ReloadDefaults() > Src URL: image-512.png --
file:///var/containers/Bundle/Application/A11D6A4A-E108-483F-86EC-BBFA10E77F72/TheAwesomeApp.app/DefaultBlocks.bundle/_default_images_/
[Verbose] ReloadDefaults() > Dest URL:
file:///var/mobile/Containers/Data/Application/6ED04DA7-077F-4AE2-AB74-2EED02932823/Documents/image-512.png
Unfortunately I've got a error for the replaceItemAt call:
[Error] ReloadDefaults() > File copy error: You don’t have permission
to save the file “image-512.png” in the folder “Documents”.
I have a recent versions of the Xcode and iOS.
I am new to swift and trying to save the file on iphone and view them using file manager app present in app store. but every time the path looks like its getting stored in my mac machine. below is code which i have written for storing a simple text file
func saveImageDocumentDirectory(){
let str = "Super long string here"
let filename = getDocumentsDirectory().appendingPathComponent("output.txt")
do {
try str.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
print(filename.path)
} catch {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
but path at which file is getting stored is printed as below
/var/mobile/Containers/Data/Application/ACBC0B24-XXXX-XXXX-XXXX-BDAA4901EA41/Documents/output.txt
In my iOS project I'm using Alamofire library to download remote documents (from a server with Basic Auth) in this way:
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent("foo.pdf")
return (filePath.url, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(myUrlRequest, to: destination).authenticate(user: user, password: password, persistence: .none).validate().response { response in
print(response)
if response.error == nil, let path = response.destinationURL?.path {
print(path)
}
}
This works great! The file is correctly downloaded in the app's Documents folder.
My problem is when user or/and password are wrong. In this case server response status is 401 Unauthorized and .validate() method correctly fails, but in my Documents folder I find the file "foo.pdf" where the content is a xml that explains the 401 error. What I would like is the file saved only if the validate doesn't fail.
My questions: is there a way, with Alamofire, to save the file just in case the response is validated? Or do I have to manually delete the file when validate fails?
I am having the similar issue at the moment. So far, the only thing I could think of is crude
if response.error != nil {
try? FileManager.default.removeItem(at: destinationURL)
}
in response closure.
I will investigate further though.
EDIT 1:
It seems this issue quite some time ago brought this behaviour https://github.com/Alamofire/Alamofire/issues/233