Move all files into another location in a Swift script - ios

To start, I am a total noob at Swift.
I am trying to move files from one location to another in Swift. For example, I have a function which lets me use bash commands within my Swift script. I simply had the following to move all files from one folder into current location: shell("mv \(currentDirectory)/archive/*.crash \(currentDirectory)").
However I was told to use the fileManager API to move files and by using filemanager I could have have better error reporting capability. I did see that Apple has the following command: https://developer.apple.com/documentation/foundation/filemanager/1414750-moveitem
EDIT**: So I have been able to figure out how to do this with the following code:
let files = try? fileManager.contentsOfDirectory(atPath: "\(currentDirectory)/archive")
if let files = files {
for file in files {
do {
try fileManager.moveItem(atPath: "\(currentDirectory)/archive/\(file)",
toPath:"\(currentDirectory)/ips/\(file)")
print(files.count)
} catch {
print("Error \(error)")
}
}
}
}
However, when I run my script, it moves the files as expected but now it is crashing my script with a Fatal error: Index out of range
See screenshot below:
Does anyone know if this is due to the contentOfDirectory throwing an empty array?

Related

initiaize object of AGSGeodatabase with file path is returning "File not found

I want to post this question on esri community, but I was not able to login there.
I created the offline geo database and showing the layers from it to the map.
My issue is when i download the geoDatabse and show the data from it is working fine for the first time.
But when I restart the app and create the AGSGeodatabase object from path then the "self.generatedGeodatabase.load" function gives error
Error Domain=com.esri.arcgis.runtime.error Code=14 "File not found" UserInfo={NSLocalizedFailureReason=, NSLocalizedDescription=File not found, Additional Message=}
my created url is :-
file:///var/mobile/Containers/Data/Application/60CF7AE1-2DE1-4FA0-805A-6140D4829E89/Documents/GeoDatabase/2018-05-134T18:29:01+0530.geodatabase
and I'm creating object is like this :-
if let geoDatabasePath = URL(string: SettingsManager.geoDatabasePath) {
self.generatedGeodatabase = AGSGeodatabase(fileURL: geoDatabasePath)
self.displayLayersFromGeodatabase()
}
and error is coming when this function runs:-
self.generatedGeodatabase.load(completion: { [weak self] (error:Error?) -> Void in
if let error = error {
print(error)
}
})
Previously I was just saving the path of the geoDatabse to preference (when creating the geoDatabse) and app is not detecting the geoDatabse at that location when I restart the app even the file is there.
The solution to this problem I find is to detect the geoDatabse path at runtime and create path using FileManager. Then it works.

Unable to load WAV to AKMidiSampler on MacOSX

I'm trying to work with AKMidiSampler on Mac OSX. I'm unable to load sample data from a file. The following code will illustrate the problem when put into the Development Playground in the AudioKit for macOS project:
import AudioKit
let sampler1 = AKMIDISampler()
sampler1.loadPath("/Users/shane/Documents/Cel1.wav")
AudioKit.output = sampler1
AudioKit.start()
sampler1.play(noteNumber: 64, velocity: 100, channel: 0)
sleep(5)
sampler1.stop(noteNumber: 64, channel: 0)
The error happens right at line 2:
AKSampler.swift:loadPath:114:Error loading audio file at /Users/shane/Documents/samples/Cel1.wav
and all I hear is the default sine tone. I've checked the obvious things, e.g. the file is quite definitely present, permissions OK (actually rwx for everybody, just in case). Earlier experiments trying to load an ESX file indicated permission errors (code -54).
Can anyone verify that AKSampler and/or AKMIDISampler actually work in OSX?
Update March 20, 2018: The AudioKit team has since made some additions to the AKSampler/AKMIDISampler API to allow loading sample files from arbitrary file paths.
I have been invited to join the AudioKit core team, and have written a new sampler engine from scratch. In the next AudioKit release (expected within a day or two), the name "AKSampler" will refer to this newer code, but users should be aware that it is not a direct replacement for the older AKSampler, which will be renamed "AKAppleSampler" to reflect the fact that it is a wrapper for Apple's built-in "AUSampler" audio unit. The AKMIDISampler class (the one most people actually use) will remain unchanged as a wrapper for AKAppleSampler.
In the AudioKit source code, loadPath(_ :) calls loadInstrument(_ : type:) which looks in the bundle for your file. See a copy of the sources here:
#objc open func loadPath(_ filePath: String) {
do {
try samplerUnit.loadInstrument(at: URL(fileURLWithPath: filePath))
} catch {
AKLog("Error loading audio file at \(filePath)")
}
}
internal func loadInstrument(_ file: String, type: String) throws {
//AKLog("filename is \(file)")
guard let url = Bundle.main.url(forResource: file, withExtension: type) else {
fatalError("file not found.")
}
do {
try samplerUnit.loadInstrument(at: url)
} catch let error as NSError {
AKLog("Error loading instrument resource \(file)")
throw error
}
}
So you need to put your audio file in the app's or playground's bundle for this to call for this to work.

iOS reading from a file

I'm trying to get my iPhone app to load text from a file into a string array, with 1 line from the file per array element.
I've created an input file as a text file using sublime text. I dragged the file (which is located inside of a folder inside of my project directory) into xCode into a folder in the same location in the project heirarchy.
I also tried adding it as a bundle (by copying the folder and renaming it with the .bundle extension), to no avail. Currently, my app has the file in 2 places (Obviously I plan to delete the unneeded version, but I'm not sure how this will work so I've left it for now).
I've written a function that I want to read my file, and assemble its contents into an array:
func readFromFile(filename: String) -> [String]? {
guard let theFile = Bundle.main.path( forResource: fileName, ofType: "txt") else {
return nil // ALWAYS returns nil here: Seems 'filename' can't be found?????
}
do { // Extract the file contents, and return them as a split string array
let fileContents = try String(contentsOfFile: theFile)
return fileContents.components(separatedBy: "\n")
} catch _ as NSError {
return nil
}
}
As it stands, the function always returns nil at the location commented in the code.
I've been working on this for ~6hrs (and tried every suggestion I could find on StackOverflow, google etc) and I'm just getting more and more confused by the differences between the various versions of Swift and intricacies of iOS development. I can't seem to find a consistent answer anywhere. I've checked the apple documentation but it's too high level with no example code for me to understand at my swift beginner level.
I also tried naming the file with a ".txt" extension but that didn't help either.
The file must certainly be named alert01.txt if you are going to refer to it as forResource: "alert01", ofType: "txt".
Loading from a bundle will not work. The file needs to be part of your project as shown in the first entry.
However, your code is not going to work because you have created a folder reference. That means the folder PanicAlertFiles is being copied with all its contents into your bundle. Your code will need to dive into that folder in order to retrieve your file. Use path(forResource:ofType:inDirectory:) to do that, or (if you don't want to have to code the file name explicitly) get the folder and then use the FileManager to examine its contents.

Download in documents directory or move file async - iOS

I am building an iOS app in which the user can download different files.
I am using an URLSessionDownloadTask and an URLSession to download a file asynchronously.When the download is finished, the destination folder is by default, the tmp/ directory.
So, when the download ends, I need to move the temporary file to another directory.For a picture or a song, this takes only 1 second maybe even less. But when the file is a video for example, it can take up to 15 seconds.
The issue
To allow the user to still interact with the app, I would like to make this move asynchronous.Each time I try to do that, the file manager throws an exception.
“CFNetworkDownload_xxxxxx.tmp” couldn’t be moved to “Downloads” because either the former doesn't exist, or the folder containing the latter doesn't exist.
What have I tried
I tried to put the call to the file manager in a background thread, it throws.
I tried to remove the destination file before calling the move method, to make sure that the file doesn't already exists.
I tried to make a call to the copy function, before removing the file from the tmp/ directory.
My code
The call to the file manager looks like that.
func simpleMove(from location: URL, to dest: URL) -> Bool {
let fileManager = FileManager.default
do {
try fileManager.moveItem(at: location, to: dest)
return true
} catch {
print("\(error.localizedDescription)")
return false
}
}
When I put that in a background thread, I do it like that.
DispatchQueue.global().async {
if !simpleMove(from: location, to: dest) {
//Failure
}
}
Questions
How can I possibly move a really large file without affecting the UI?
It would be an even better solution to download the file directly in a permanent directory. How can I do that?
When I make the call to my simpleMove(from:to:) synchronously, it works perfectly.So, why the error says that the destination directory doesn't exists? (or something like that, I'm not sure of the meaning of that error)
Thanks.
Note
The code above is written in Swift 3, but if you have an Objective-C or a Swift 2 answer,feel free to share it as well!
Amusingly, the correct answer to this was posted in another question, where it was not the correct answer.
The solution is covered in Apple's Documentation where they state:
location
A file URL for the temporary file. Because the file is temporary, you must either open the file for reading or move it to a permanent location in your app’s sandbox container directory before returning from this delegate method.
If you choose to open the file for reading, you should do the actual reading in another thread to avoid blocking the delegate queue.
You are probably calling simpleMove from the success handler for the DownloadTask. When you call simpleMove on a background thread, the success handler returns and your temp file is cleaned up before simpleMove is even called.
The solution is to do as Apple says and open the file for reading:
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
do {
let file: FileHandle = try FileHandle(forReadingFrom: location)
DispatchQueue.global().async {
let data = file.readDataToEndOfFile()
FileManager().createFile(atPath: destination, contents: data, attributes: nil)
}
} catch {
// Handle error
}
}
I came across the same issue but i solve it.
First check that the file is exist in that path because i got issue because of the path extension are different of location URL. i was trying to rename audio but path extension was different(eg. mp3 to m4a)
Also in case there is any other file already exists at destination path
this issue arise.
So first try to check file exists at location where you by using
let fileManager = FileManager.default
if fileManager.fileExists(atPath: location.path) {
do {
try fileManager.moveItem(at: location, to: dest)
return true
} catch {
print("\(error.localizedDescription)")
return false
}
}
Hope this will help you

Unable to open a realm at path

I am trying to use a bundled realm file without success. I know that my realm file was copied successfully to my application’s Directory but I ca not read it.
fatal error: 'try!' expression unexpectedly raised an error: "Unable
to open a realm at path
'/Users/…/Library/Developer/CoreSimulator/Devices/…/data/Containers/Data/Application/…/Documents/default-v1.realm'.
Please use a path where your app has read-write permissions."
func fullPathToFileInAppDocumentsDir(fileName: String) -> String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,NSSearchPathDomainMask.UserDomainMask,true)
let documentsDirectory = paths[0] as NSString
let fullPathToTheFile = documentsDirectory.stringByAppendingPathComponent(fileName)
return fullPathToTheFile
}
In didFinishLaunchingWithOptions:
let fileInDocuments = fullPathToFileInAppDocumentsDir("default-v1.realm")
if !NSFileManager.defaultManager().fileExistsAtPath(fileInDocuments) {
let bundle = NSBundle.mainBundle()
let fileInBundle = bundle.pathForResource("default-v1", ofType: "realm")
let fileManager = NSFileManager.defaultManager()
do {
try fileManager.copyItemAtPath(fileInBundle!, toPath: fileInDocuments)
} catch { print(error) }
}
And setting the configuration used for the default Realm:
var config = Realm.Configuration()
config.path = fileInDocuments
Realm.Configuration.defaultConfiguration = config
let realm = try! Realm(configuration: config) // It fails here!!! :-)
As the documentation suggests, I have tried as well to open it directly from the bundle path by setting readOnly to true on the Realm.Configuration object. I am not sure if this is something related to Realm or if I am overlooking something with the file system…. I have also tried to store the file in the Library folder.
Realm 0.97.0
Xcode Version 7.1.1
I tried to open the realm file using Realm's browser app and the file does not open anymore. It has now new permissions: Write only (Dropbox). So, I decided to change the file permission back to read/write using file manager’s setAttributes method. Here is how I did it:
// rw rw r : Attention for octal-literal in Swift "0o".
let permission = NSNumber(short: 0o664)
do {
try fileManager.setAttributes([NSFilePosixPermissions:permission], ofItemAtPath: fileInDocuments)
} catch { print(error) }
The realm file can now be open at this path.
That exception gets thrown whenever a low level I/O operation is denied permission to the file you've specified (You can check it out on Realm's GitHub account).
Even though everything seems correct in your sample code there, something must be set incorrectly with the file location (Whether it be the file path to your bundle's Realm file, or the destination path) to be causing that error.
A couple of things I can recommend trying out.
Through breakpoints/logging, manually double-check that both fileInDocuments and fileInBundle are being correctly created and are pointing at the locations you were expecting.
When running the app in the Simulator, use a tool like SimPholders to track down the Documents directory of your app on your computer, and visually ensure that the Realm file is being properly copied to where you're expecting.
If the Realm file is in the right place, you can also Realm's Browser app to try opening the Realm file to ensure that the file was copied correctly and still opens properly.
Try testing the code on a proper iOS device to see if the same error is occurring on the native system.
If all else fails, try doing some Realm operations with the default Realm (Which will simply deposit a default.realm file in your Documents directory), just to completely discount there isn't something wrong with your file system
Let me know how you go with that, and if you still can't work out the problem, we can keep looking. :)
This will occur if you have your realm file open in Realm Studio at same time you relaunch your app. Basically in this case Realm can't get write permissions if Studio already has them.
To add to the solution based on what I've discovered, make note of what error Realm reports when it throws the exception, as well as the type of Error that is passed.
As of writing, Realm documents their errors here:
https://realm.io/docs/objc/latest/api/Enums/RLMError.html
What this means is that you can find out if your Realm file has permissions problems and react to those based on Realm passing you a RLMErrorFilePermissionDenied. Or if the file doesn't exist with RLMErrorFileNotFound.
The tricky thing I'm finding is when you get a more generic RLMErrorFileAccess, but that's for another question on Stack Overflow...
I had the same issue and tried too many ways to fix it. The easiest way to fix this problem is manually creation of the folder XCode cannot reach '/Users/…/Library/Developer/CoreSimulator/Devices/…/data/Containers/Data/Application/…/Documents/...' as explained at https://docs.realm.io/sync/using-synced-realms/errors#unable-to-open-realm-at-path-less-than-path-greater-than-make_dir-failed-no-such-file-or-directory
Once you created this folder and run the project, XCode creates the Realm files inside this folder automatically.

Resources