Cannot delete element in directory in Swift [duplicate] - swift

How is it possible?
let exists = NSFileManager.defaultManager().fileExistsAtPath(path.absoluteString)
print("exists: \(exists)") //false
This is path.absoluteString
//file:///Users/kuna/Library/Developer/CoreSimulator/Devices/92BD140D-5C14-43C4-80D6-904BB9594ED6/data/Containers/Data/Application/5B818832-BB19-4047-A7F8-1487F36868D6/Documents/wishlists/68/147/128/IMG_0006.PNG
And you can see it is there where it should be:
What is going on?

(The code in this answer has been updated for Swift 3 and later.)
Apparently your path variable is a NSURL (describing a file path). To get the path as
a string, use the path property, not absoluteString:
let exists = FileManager.default.fileExists(atPath: path.path)
absoluteString returns the URL in a string format, including
the file: scheme etc.
Example:
let url = URL(fileURLWithPath: "/path/to/foo.txt")
// This is what you did:
print(url.absoluteString)
// Output: file:///path/to/foo.txt
// This is what you want:
print(url.path)
// Output: /path/to/foo.txt

If you want to check if a path exist,you should check path
let url = NSURL(string: "balabala")
let path = url?.path
//Check path

Related

NSArrayURL , userDefault filePath and URL

I have one pdf source code and I want to add the Url in Array and use UserDefault
let defaults = UserDefaults.standard
struct Constants {
static let myKeyURL = "myKeyUrl"
}
I download the Pdf Like This
let documentsPath =NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileName = urlString as NSString;
let filePath="\(documentsPath)/\(fileName.lastPathComponent)";
After I save the Path like This
var arrayUrl = [String]()
arrayUrl.append(filePath)
self.defaults.set(arrayUrl, forKey: Constants.myKeyURL)
Now I want to Read
var arrayUrl = [String]()
defaults.stringArray(forKey: Constants.myKeyURL)
arrayUrl = defaults.stringArray(forKey: Constants.myKeyURL)!
I need to Read in This Model
documents = arrayUrl.flatMap { PDFDocument(url: $0 ) }
But I received
Cannot convert value of type 'String' to expected argument type 'URL'
I need this URL (arrayUrl) File in this format file:///private/var/mobile/Containers/Data/Application/----/Documents/Sample.pdf
The error is clear:
PDFDocument(url: expects URL, you pass String which is a classic type mismatch.
You have to create URL instances from the strings
documents = arrayUrl.flatMap { PDFDocument(url: URL(fileURLWithPath: $0) ) }
However you are discouraged from saving the full path because the path to the Documents folder changes. Save only the file name or relative path and get the actual path to the Documents folder on each application launch.

NSKeyedArchiver.archiveRootObject fails to save

I have a group of custom objects that I'm converting to NSMutableDictionary's, and then creating an array out of them (this part is currently working as expected).
I'm then attempting to save that array of data as a file using NSKeyedArchiver. However, the result of NSKeyedArchiver.archiveRootObject always returns false.
Below is my logic for saving - am I missing something obvious, or perhaps is this the wrong approach? Thank you!
var groupsArray = [Any?]()
for group in file!.groups{
for obj in group.children {
let objDict = obj.convertToDictionary()
groupsArray.append(objDict)
}
}
let documents: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath: String = URL(fileURLWithPath: documents).appendingPathComponent("file.archive").absoluteString
let save: Bool = NSKeyedArchiver.archiveRootObject(groupsArray, toFile: filePath)
EDIT: This also fails if trying to save to the .desktop or the .caches directories.
The issue here is .absoultestring. If the URL object contains a file URL, then we should use .path for working with FileManager or PathUtilities etc. So here replacing .absoultestring with .path will solve the issue
for more details about their difference please refer this answer
try this method to save
1.Method returns filepath.
func filePath(key:String) -> String {
let manager = FileManager.default
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
return (url!.appendingPathComponent(key).path)
}
2.Code to save to a file using NSKeyedArchiver.
NSKeyedArchiver.archiveRootObject(groupsArray, toFile: filePath(key: "file.archive"))

"Bash like" paths to NSURL or Foundation path

In most command line tools, paths to files can be specified using formats like those: ../someFile, ~/anotherFile, /foo/bar. How can I init a valid Swift URL or (Foundation) path from such a path?
EDIT:
Maybe a code example is clearer, say I want to init a String from path and I have a foo file in my user directory, doing this:
try String(contentsOfFile: "~/foo")
Doesn't work (error is file does not exist)
In Swift, you can do :
let str = "~/Documents"
// NSString has a function for decoding this, not available to String:
let str2 = (str as NSString).standardizingPath as String
// Swift deprecated the String path manipulation functions,
// but supplies them as part of NSURL:
let url = URL(fileURLWithPath: str)
let url2 = url.standardizedFileURL // Expands the URL

How do I parse out only the files actual name and not the full path?

I have some code that (I thought) could split a filename from its file type. For example, "filename.txt" -> ["filename, "txt"].
However, I didn't realize that when I use a dialog box to open a file name, I get the full path (rookie mistake, I know). For example, this is what my function is returning:
filename_array: ["/home/user/Downloads/filename", "txt"]
How do I remove the path stuff and only return the filename part?
Apple has been trying to get rid of all the "path as string" style and migrate them into URL. The path manipulation API has been removed from String and moved to URL:
let path = "/home/user/Downloads/filename.txt"
let url = URL(fileURLWithPath: path)
let fileNameOnly = url.deletingPathExtension().lastPathComponent // filename
let fileExtention = url.pathExtension // txt
Or you can do it old-school style with NSString:
let path = "/home/user/Downloads/filename.txt"
let fileName = (path as NSString).lastPathComponent as NSString // filename.txt
let fileNameOnly = fileName.deletingPathExtension // filename
let fileExtension = fileName.pathExtension // txt

Where do I get the OSX volume for replacing "/" [duplicate]

When using
let directoryEnumerator = FileManager().enumerator(at: ...
in Swift 3, I get all files from the folder, e.g.
"file:///Volumes/MacOS/fasttemp/Fotos/"
The results are not including the leading path (here "/Volumes/MacOS"). So I get
"file:///fasttemp/Fotos/2005/"
How can I get the fullpath (directly from the enumerator) or convert them. I want to use URL functions, not string function manipulating by assumptions.
If "MacOS" is the name of your current startup disk then "/Volumes/MacOS" is a symbolic link to "/", so both "/fasttemp/Fotos/2005/" and "/Volumes/MacOS/fasttemp/Fotos/" are absolute paths to the same file.
In order to get a unique file name representation you can query
a URL for its canonical path. Example:
let url = URL(fileURLWithPath: "/Volumes/MacOS/Applications/Utilities/")
if let cp = (try? url.resourceValues(forKeys: [.canonicalPathKey]))?.canonicalPath {
print(cp)
}
// Output: "/Applications/Utilities"
This requires macOS 10.12/iOS 10 or later. On older systems you can
use the realpath() system call:
if let rp = url.withUnsafeFileSystemRepresentation ({ realpath($0, nil) }) {
let fullUrl = URL(fileURLWithFileSystemRepresentation: rp, isDirectory: true, relativeTo: nil)
free(rp)
print(fullUrl.path)
}
// Output: "/Applications/Utilities"
Note that you want to use URL wherever possible, from the NSURL documentation:
URL objects are the preferred way to refer to local files. Most
objects that read data from or write data to a file have methods that
accept an NSURL object instead of a pathname as the file reference.
Here’s an example of how to get all the objects from a directory:
import Foundation
let manager = FileManager.default
// Get URL for the current user’s Documents directory
// Use URL instead of path, it’s more flexible and preferred
if let documents = manager.urls(for: .documentDirectory, in: .userDomainMask).first,
// Get an Enumerator for the paths of all the objects in the directory
// but do not descend into directories or packages
let directoryEnumerator = manager.enumerator(at: documents, includingPropertiesForKeys: [URLResourceKey.pathKey], options: [.skipsSubdirectoryDescendants, .skipsPackageDescendants]) {
// iterate through the objects (files, directories, etc.) in the directory
for path in directoryEnumerator {
print(path)
}
}