I have created a folder inside documents directory using :
fileManager.createDirectory(atPath:ziPFolderPath,withIntermediateDirectories: false, attributes: nil)
In this folder I have placed few files.
Later in the app, I want to delete not just the files inside the above folder, but also the folder.
FileManager supports removeItem function but I am wondering if it removes the folder as well.
Yes it will delete folder also.
From the documentation of: - removeItem(at:)
Removes the file or directory at the specified URL.
From the documentation of: - removeItem(atPath:)
Removes the file or directory at the specified path.
Edit: You can call it like this way.
try? FileManager.default.removeItem(at: URL(fileURLWithPath: ziPFolderPath))
//OR
try? FileManager.default.removeItem(atPath: ziPFolderPath)
Swift 5
Also you should check if file exist at path or not and check for error also.
do {
let fileManager = FileManager.default
// Check if file exists
if fileManager.fileExists(atPath: urlfilePath) {
// Delete file
try fileManager.removeItem(atPath: urlfilePath)
} else {
print("File does not exist")
}
} catch {
print("An error took place: \(error)")
}
-(BOOL)removeItemAtPath:(NSString *)path
error:(NSError * _Nullable *)error;
path is the string indicating directory or folder to remove. Its a NSFileManager method.
you can also check here https://developer.apple.com/reference/foundation/nsfilemanager/1408573-removeitematpath?language=objc
Related
I have an iOS application that uses UIDocumentPickerController to present the user with a dialog where they can pick the location of a directory containing files for upload
This is working just fine in most cases but if they pick a directory that is located on their iCloud account, DocumentPickerViewController returns a URL that produces unusable file URLs when enumerating the iCloud directory
Here is how I set it up:
var documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypeFolder as String], in: .open)
documentPicker.delegate = self
sView.present(documentPicker, animated: true, completion: nil)
And here is how I enumerate the files in the iCloud directory that they have chosen:
NSFileCoordinator().coordinate(readingItemAt: url, error: &error) { (url) in
let access = url.startAccessingSecurityScopedResource()
var directoryContents: [URL]
do {
let keys : [URLResourceKey] = [.nameKey, .isDirectoryKey]
directoryContents = try FileManager.default.contentsOfDirectory(
at: url,
includingPropertiesForKeys: keys)
} catch {
print("error \(error))")
if access {
url.stopAccessingSecurityScopedResource()
}
return
}
if access {
url.stopAccessingSecurityScopedResource()
}
}
For each file, I pass it to FileManager to copy into the application's sandbox:
for fromURL in directoryContents {
var lastPath = fromURL.lastPathComponent
print("Lastpath is \(lastPath)")
let toURL: URL = documentURL.appendingPathComponent(lastPath)
print("fromURL - \(fromURL)")
print("toURL \(toURL)")
let fM = FileManager.default
if(fM.fileExists(atPath: toURL.path)) {
exists += 1
} else {
do {
let access = url.startAccessingSecurityScopedResource()
try fM.copyItem(at: fromURL, to: toURL)
if access {
url.stopAccessingSecurityScopedResource()
}
count += 1
} catch {
print("Error on file copy \(error)")
}
}
}
This works just fine if the directory is on, say, an external USB drive but if I point it to iCloud, this is what I get:
fromURL - file:///Users/greg/Library/Developer/CoreSimulator/Devices/FFDED20B-B142-4FC6-BA8F-C1DC193E2AB7/data/Library/Mobile%20Documents/com~apple~CloudDocs/Savvy/SavvyLink/SmallEngineDataRepo/.Flt0002_20180913P.csv.icloud
toURL file:///Users/greg/Library/Developer/CoreSimulator/Devices/FFDED20B-B142-4FC6-BA8F-C1DC193E2AB7/data/Containers/Data/Application/167AC69D-494C-4CB1-8A36-E230C5303F30/Documents/.Flt0002_20180913P.csv.icloud
Note the file names have a dot (.) prepended and a .iCloud postpended. If I look in my application's sandbox I see the files in the Documents directory but the contents of the files are NOT the contents of the files on iCloud but instead look to be themselves some kind of a URL
Thanks for any insight into what is going on here and what I am missing
What I expect to happen is to be able to take the URLs returned when enumerating the files in the iCloud directory and then pass those URLs to FileManager.copyItems to copy them into my application's sandbox
As I said, this works just fine for directories located on (say) USB drives but when used for directories on iCloud it results in copying in files with very different contents than what is on the original files in iCloud and with names changed to have a "." prepended and ".iCloud" postpended
I created a file in the document directory and for some reason when I try to delete it using the code below, it doesn't get deleted. The code doesn't throw any errors, but the file is still there
let fileManager = FileManager.default
if let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let filePath = documentDirectory.appendingPathComponent("data.json")
do {
try fileManager.removeItem(atPath: filePath.path)
} catch let error as NSError {
print(error.localizedDescription)
}
}
I also tried to put it inside another folder and remove the folder but still the same problem.
This is the path where the file is stored :
Users/user1/Library/Developer/CoreSimulator/Devices/76AFDB69-75C8-464E-93F2-6ABF622068FD/data/Containers/Data/Application/7D268156-977A-4A3C-834B-6B13FA3DE76D/Documents/
you can try like below
if let filePath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("data.json"), fileManager.fileExists(atPath: filePath.path) {
do {
try fileManager.removeItem(atPath: filePath.path)
} catch let error as NSError {
print(error.localizedDescription)
}
}
The code doesn't throw any errors, but the file is still there
No, it isn't. The problem is with the way you are checking to see whether "the file is still there". You are looking on your computer for the file. But iOS files are sandboxed. At the time you are looking, the path where the file was is completely different from your claimed path:
Users/user1/Library/Developer/CoreSimulator/Devices/76AFDB69-75C8-464E-93F2-6ABF622068FD/data/Containers/Data/Application/7D268156-977A-4A3C-834B-6B13FA3DE76D/Documents/
Such paths are not permanent. They are meaningless and should not be used. The only way to know whether the file is still there is with more code from inside iOS, i.e. ask the FileManager. When you do, you will find that you are, indeed, deleting the file successfully.
I have a few items that are saved to the documents directory. I currently need those to be moved programmatically to another directory. I created the new directory successfully, but it doesn't seem to be looking at that when using FileManager.default.moveItem.
Code used to created directory.
let path = getDocumentsDirectory().appendingPathComponent("Media").path
do{
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil)
print("\nDIRECTORY 'Media' CREATED")
}catch {
print("\nDIRECTORY 'Media' WAS NOT ABLE TO BE CREATED")
print("ERROR - \(error)")
}
I use this code to check my URL.
let mediaURL = getDocumentsDirectory().appendingPathComponent("Media")
print("\nMEDIA URL: \(mediaURL)")
Which outputs this.
MEDIA URL:file:///Users/joseph/Library/Developer/CoreSimulator/Devices/552B72BF-8929-40EE-A75B-4574D3D2918A/data/Containers/Data/Application/E168B872-6A1D-4D78-B460-D45194088E5B/Documents/Media/
Here is the code I'm using to move the items.
do{
try FileManager.default.moveItem(at: url, to: mediaURL)
print("\nFILE MOVED TO NEW MEDIA PATH SUCCESSFULLY")
}catch {
print("\nCOULDN'T MOVE FILE TO NEW MEDIA PATH")
print("ERROR - \(error)")
}
Here is the error I'm receiving for each item that I try to move.
COULDN'T MOVE FILE TO NEW MEDIA PATH
ERROR - Error Domain=NSCocoaErrorDomain Code=516 "“image_5” couldn’t be moved to “Documents” because an item with the same name already exists." UserInfo= {NSSourceFilePathErrorKey=/Users/joseph/Library/Developer/CoreSimulator/Devices/552B72BF-8929-40EE-A75B-4574D3D2918A/data/Containers/Data/Application/E168B872-6A1D-4D78-B460-D45194088E5B/Documents/image_5, NSUserStringVariant=(
Move
), NSDestinationFilePath=/Users/joseph/Library/Developer/CoreSimulator/Devices/552B72BF-8929-40EE-A75B-4574D3D2918A/data/Containers/Data/Application/E168B872-6A1D-4D78-B460-D45194088E5B/Documents/Media, NSFilePath=/Users/joseph/Library/Developer/CoreSimulator/Devices/552B72BF-8929-40EE-A75B-4574D3D2918A/data/Containers/Data/Application/E168B872-6A1D-4D78-B460-D45194088E5B/Documents/image_5, NSUnderlyingError=0x60000024fff0 {Error Domain=NSPOSIXErrorDomain Code=17 "File exists"}}
The media directory should be empty, as it is newly created, so the error I'm receiving is a bit confusing. It's also saying it's trying to move it to 'Documents', but it should be moving to 'Media'.What is causing this issue, and how can I resolve it? I'm just trying to move the items saved in 'Documents' to the new directory, 'Media'.
You must append the file name to the destination URL. Per the docs:
The new location for the item in srcURL. The URL in this parameter must not be a file reference URL and must include the name of the file or directory in its new location. This parameter must not be nil.
Delete the old file if exist
let url = NSUrl(string: "...")
if NSFileManager.defaultManager().fileExistsAtPath(url.path!) {
try! NSFileManager.defaultManager().removeItemAtURL(url)
}
Update:
Swift 5.1.2
let url = URL(string: mp3FilePath)
if FileManager.default.fileExists(atPath: url!.path) {
try! FileManager.default.removeItem(at: url!)
}
This worked for me - Add the name of file too in destination path
let nameFile = (songPath as NSString).lastPathComponent
let fileDest = destinationDirectoryPath + "/" + nameFile
//Now move the song files
try fileManager.moveItem(atPath: sourceFilePath, toPath: fileDest)
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've put a "restaurants.txt" file in the same directory with MenuViewController.swift.
Then I put this code in viewDidLoad() of MenuViewController to read the file.
if let path = NSBundle.mainBundle().pathForResource("restaurants", ofType: "txt") {
if let content = try? String(contentsOfFile: path, encoding: NSUTF8StringEncoding) {
print(content)
} else {
print("error1")
}
} else {
print("error")
}
Then I get "error1" in my console.
How can I read the file in the same directory of the swift file?
Or do I have to put my "restaurants.txt" file somewhere else?
Add the file to the target:
Select the file
In the Project Navigator command1 select the file icon
Under "Target Membership" click the checkbox for the file.
1) If you wish to read content of a text file, even without inserting it to your project, you may also use NSFileMananger. The following code works, the only drawback - you need to state full path.
let fullPath = "/your/full/path/restaurants.txt"
if NSFileManager.defaultManager().fileExistsAtPath(fullPath){
do
{
let content = try String(contentsOfFile: fullPath, encoding: NSUTF8StringEncoding)
print("\(content)")
}
catch let error as NSError
{
print("error reading file: \(error)")
}
}
2) If you do mind the hardcode, and want it more generic - you will have to change Settings in the Build in Xcode. See here:
Locate source project directory in Swift