This question already has an answer here:
NSArrayURL , userDefault filePath and URL
(1 answer)
Closed 5 years ago.
I Download pdf file Like This And Saved the Path in Userdefault
var documents = PDFDocument
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileName = urlString as NSString;
var arrayUrl = [String]()
arrayUrl.append(filePath)
self.defaults.set(arrayUrl, forKey: Constants.myKeyURL)
The First Time when App Run This documents get Value Well But Next Time When I don't need to Download Again documents it's Null but The ArrayURL ints same Value !!
var arrayUrl = [String]()
self.defaults.stringArray(forKey: Constants.myKeyURL)
arrayUrl = self.defaults.stringArray(forKey: Constants.myKeyURL)!
self.documents = arrayUrl.flatMap { PDFDocument(url: URL(fileURLWithPath: $0) ) }
print(self.documents)
DispatchQueue.main.async {
self.tableView.reloadData()
}
You shouldn't save the file's fullpath, for security reasons your app's container name gets changed, so the document directory would also changed every time your app gets launched/reloaded.
Instead, save only the file's name along its extension (use the property lastPathComponent from the downloaded url), and whenever you want to load these files just append the name to the document directory.
Related
I have to rename some files in a directory in the Documents directory. I'm trying with URLResourceValues:
let fileURLs = try! FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil)
fileURLS.forEach { fileURL in
// calculate newFileName
var resourceValues = URLResourceValues()
resourceValues.name = newFilename
var mutableFileURL = fileURL
try! mutableFileURL.setResourceValues(resourceValues)
}
After setting resourceValues.name I see this in the console...
key NSMutableString "NSURLNameKey" 0x00000001e7a8a368
value NSString "newName.jpg" 0x0000000283f61fe0
So that part is working. The try! completes without crashing so there were no errors thrown. But mutableFileURL is unchanged. It's got the old name, not the new name.
I see in the docs that setting read-only properties or setting properties not supported will be ignored and will not throw an error. But in my research I see this approach used commonly for renaming files. And I don't think it's a write access thing because if I use the old way it works fine:
try! FileManager.default.moveItem(at: fileURL, to: newFileURL)
What could I be missing here?
P.S. app targets iOS 14, running on a real device running iOS 16.1
You have not shown how you know things didn't work. But you say:
But mutableFileURL is unchanged
Your code isn't supposed to change mutableFileURL. If you're looking at mutableFileURL to see what happened, that's the problem.
The URL here is just a pointer to the file on disk. That's the whole point of the setResourceValues approach. Your code changes the name of the file on disk (and mutableFileURL, the pointer, is now invalid and should just be thrown away).
If you re-fetch the contents of the documents directory, you'll see that your code worked just fine.
Complete example, showing both what I think you are doing and how to do this correctly:
// --- create the file ---
let fm = FileManager.default
let docsurl = try fm.url(
for: .documentDirectory, in: .userDomainMask,
appropriateFor: nil, create: false
)
let newurl = docsurl.appending(path: "howdy.txt")
try "howdy".write(to: newurl, atomically: true, encoding: .utf8)
let arr = try fm.contentsOfDirectory(
at: docsurl, includingPropertiesForKeys: nil
)
arr.forEach { print($0.lastPathComponent) }
// howdy.txt
// --- rename the file ---
var values = URLResourceValues()
values.name = "hello.txt"
var mutableurl = newurl
try mutableurl.setResourceValues(values)
// --- how did we do? this is _not_ the way:
print(mutableurl)
// file:///.../Documents/howdy.txt
// --- how did we do? this _is_ the way
let arr2 = try fm.contentsOfDirectory(
at: docsurl, includingPropertiesForKeys: nil
)
arr2.forEach { print($0.lastPathComponent) }
// hello.txt
I have encryptions in the form of dictionaries that I want to save to the document directory. I also want to be able to retrieve these dictionaries from the document directory to decrypt within the app. How can I write/read dictionaries to/from the document directory?
Dictionary has its own write method which writes a property list representation of the contents of the dictionary to a given URL. You can do it using below code:
Write
// Get application document directory path array
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
let fileName = "users"
if let documentPath = paths.first {
let filePath = NSMutableString(string: documentPath).appendingPathComponent(fileName)
let URL = NSURL.fileURL(withPath: filePath)
let dictionary = NSMutableDictionary(capacity: 0)
dictionary.setValue("valu1", forKey: "key1")
dictionary.setValue("valu2", forKey: "key2")
let success = dictionary.write(to: URL, atomically: true)
print("write: ", success)
}
Read
if let dictionary = NSMutableDictionary(contentsOf: URL){
print(dictionary)
}
Hope, it will work.
Steps include
Get Document URL
Write Date to File
Saving to Disk
Make use of syntax from here:
https://stackoverflow.com/a/26557965/6342609
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
How to get the filename from the given file path string?
For example if I have a filepath string as
file:///Users/DeveloperTeam/Library/Developer/CoreSimulator/Devices/F33222DF-D8F0-448B-A127-C5B03C64D0DC/data/Containers/Data/Application/5D0A6264-6007-4E69-A63B-D77868EA1807/tmp/trim.D152E6EA-D19D-4E3F-8110-6EACB2833CE3.MOV
and I would like to get the return result as
trim.D152E6EA-D19D-4E3F-8110-6EACB2833CE3.MOV
Objective C
NSString* theFileName = [string lastPathComponent]
Swift
let theFileName = (string as NSString).lastPathComponent
SWIFT 3.x or SWIFT 4:
Shortest and cleanest way of doing this is below. In this example url variable is type of URL in this way we can have a human readable String result of the full file name with extension like My file name.txt and Not like My%20file%20name.txt
// Result like: My file name.txt
let fileName = url.lastPathComponent
If you want to get the current file name such as for logging purposes, I use this.
Swift 4
URL(fileURLWithPath: #file).lastPathComponent
Swift 2:
var file_name = NSURL(fileURLWithPath: path_to_file).lastPathComponent!
let theURL = URL(string: "yourURL/somePDF.pdf") //use your URL
let fileNameWithExt = theURL?.lastPathComponent //somePDF.pdf
let fileNameLessExt = theURL?.deletingPathExtension().lastPathComponent //somePDF
In order for this to work your url must be of type URL not a string so don't convert it to a string before hand.
You can copy and paste this code directly into playground to see how it works.
Try this
let filename: String = "your file name"
let pathExtention = filename.pathExtension
let pathPrefix = filename.stringByDeletingPathExtension
Updated :
extension String {
var fileURL: URL {
return URL(fileURLWithPath: self)
}
var pathExtension: String {
return fileURL.pathExtension
}
var lastPathComponent: String {
return fileURL.lastPathComponent
}
}
Hope it helps.
Below code is working for me in Swift 4.X
let filename = (self.pdfURL as NSString).lastPathComponent // pdfURL is your file url
let fileExtention = (filename as NSString).pathExtension // get your file extension
let pathPrefix = (filename as NSString).deletingPathExtension // File name without extension
self.lblFileName.text = pathPrefix // Print name on Label
You can pass the url in fileUrl, like I did below:-
let fileUrl: String = "https://www.himgs.com/imagenes/hello/social/hello-fb-logo.png" // Pass the URL
let lastPathComponent = URL.init(string: fileUrl)?.lastPathComponent ?? "" // With this you will get last path component
let fileNameWithExtension = lastPathComponent
//This last path component will provide you file Name with extension.
I've done some performance tests (iOS 14, real device, release configuration):
(#file as NSString).lastPathComponent // The fastest option.
URL(string: #file)!.lastPathComponent // 2.5 times slower than NSString.
#file.components(separatedBy: "/").last! // 7 times slower than NSString.
Bonus:
URL(fileURLWithPath: #file, isDirectory: false).lastPathComponent // About the same as URL(string:).
URL(fileURLWithPath: #file).lastPathComponent // 2.5 times slower than with explicit isDirectory.
Swift 5. This one works faster than both URL and NSString options:
path.components(separatedBy: "/").last
To retrieve filename without its extension from a URL in Swift >= 4.2:
let urlWithoutFileExtension: URL = originalFileUrl.deletingPathExtension()
let fileNameWithoutExtension: String = urlWithoutFileExtension.lastPathComponent
Creates unique "file name" form url including two previous folders
func createFileNameFromURL (colorUrl: URL) -> String {
var arrayFolders = colorUrl.pathComponents
// -3 because last element from url is "file name" and 2 previous are folders on server
let indx = arrayFolders.count - 3
var fileName = ""
switch indx{
case 0...:
fileName = arrayFolders[indx] + arrayFolders[indx+1] + arrayFolders[indx+2]
case -1:
fileName = arrayFolders[indx+1] + arrayFolders[indx+2]
case -2:
fileName = arrayFolders[indx+2]
default:
break
}
return fileName
}
I have a folder with 4 subfolders in my iOS application with each of these containing about 20 files each. I would like to be able to iterate through each folder and print out the filenames. I am not sure how to go about doing this.
Here is what I have tried:
let docsPath = NSBundle.mainBundle().resourcePath! + "/Samples";
let fileManager = NSFileManager.defaultManager()
var error: NSError?
let docsArray = fileManager.contentsOfDirectoryAtPath(docsPath, error:&error)
println(docsArray)
This prints out nil. I expect it to print out each of the filenames. How do I make this happen?
You have two problems here:
1)
Check your built app to see if "Samples" is really ending up in the built binary. From the error of "The operation couldn’t be completed", I'm thinking you aren't copying "Samples" into the compiled app bundle or at least into the place you're expecting it to be.
2)
The call you're doing will give you the contents of the folder, but not the contents of the subfolders which is what you really want to list.
Use NSDirectoryEnumerator instead to get the contents of that folder and subfolders. Here is a related question that might give you one direction to go.
You can use the NSFileManager's enumerator if you want to get all the files including inside subdirectories.
Simple example:
if let enumerator = fileManager.enumeratorAtURL(docsPath, includingPropertiesForKeys: nil, options: nil, errorHandler: nil) {
while let url = enumerator.nextObject() as? NSURL {
println(url)
}
}
Nevermind, I figured it out:
var docsPath = NSBundle.mainBundle().resourcePath! + "/Snare";
let fileManager = NSFileManager.defaultManager()
var error: NSError?
let docsArray = fileManager.contentsOfDirectoryAtPath(docsPath, error:&error)
//println(error!.localizedDescription)
println(docsArray)
for filename in docsArray!
{
let subfolderPath = docsPath + "/"+(filename as! String)
println(docsPath)
let subarray = fileManager.contentsOfDirectoryAtPath(subfolderPath, error: &error)
println(subarray)
}