read file content and get the values back - ios

I have an function to write some numbers to a file
fun writeNumToFile -> Void {
//get Documents’ path
let docPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last as? String
let filePath = docPath.stringByAppendingPathComponent(“myFlie.txt”)
//the count is NOT the count of elements in the array below.
//think it as an independent constant.
let count = 10
//Write count to file
String(count).writeToFile(filePath, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
//Write an array of numbers to file
for idx in [1,2,3] {
String(idx as! String).writeToFile(filePath, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
}
}
Now I want to read the numbers back from file, I know I can read the content of file by:
let fileContent = String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding, error: nil)
but how can I get count & [1,2,3] array back once I get the content?

You are writing code as if you are using low-level file i/o. You're not. The writeToFile:atomically: methods that you are using overwrite a file with new contents, not append data to an existing file. your second write deletes the contents of your first write.
NSArray supports the writeToFile:atomically: method, and a [String] array should be inter-operable with NSArray.
You should be able to simply say:
let array = [1, 2, 3]
let ok = array .writeToFile(filePath, atomically: false)
Then later,
let array = NSArray.contentsOfFile(filePath)
I say "should be able to" because I am still learning the subtleties of interaction between Swift and the Foundation classes.
EDIT:
If you need to save multiple discrete things into a file, create a dictionary:
let someValue = 42
let anArray = [1, 2, 3]
let aDictionary = [
"someValue": someValue,
"array": anArray]
let ok = aDictionary.writeToFile(filePath, atomically: false)
and to read it:
let aDictionary = NSDictionary(contentsOfFile: filePath)
let someValue = aDictionary["someValue"] as! Int
let anArray = aDictionary["array"] as! [Int]
There is no need to save the number of items in the array separately. The array is able to reconstitute itself from the file contents, including the correct count of elements.
EDIT #2:
Note that iOS includes the C file i/o library, which should be callable from Swift. If you are glutton for punishment you could do what you are trying to do using fopen(), fseek(), fwrite(), etc. (But don't. It's much more work, much more error-prone, and a non-standard way of doing it in iOS or Mac OS.)

Related

Get array of tuples from txt file

I've txt file with content:
("All our dreams can come true, if we have the courage to pursue them.","Walt Disney")
("The secret of getting ahead is getting started","Mark Twain")
I want to get array of tuples from it with type [(String, String)]. I try to use code:
do {
if let path = Bundle.main.path(forResource: "quotes", ofType: "txt"){
let data = try String(contentsOfFile: path, encoding: .utf8)
let arrayOfStrings = data.components(separatedBy: "\n")
print(arrayOfStrings[0])
}
} catch let err as NSError {
// do something with Error
print(err)
}
But with it I cannot get tuple values. How I can get array of tuples from txt file with Swift?
As already mentioned in comments by Larme it would be better to properly format your text. If you can't change the text format you woill need to manually parse its contents:
let data = """
("All our dreams can come true, if we have the courage to pursue them.","Walt Disney")
("The secret of getting ahead is getting started","Mark Twain")
"""
let tuples = data.split(whereSeparator: \.isNewline)
.compactMap { line -> (Substring,Substring)? in
let comps = line.components(separatedBy: #"",""#)
guard comps.count == 2,
let lhs = comps.first?.dropFirst(2),
let rhs = comps.last?.dropLast(2) else { return nil }
return (lhs,rhs)
}
for tuple in tuples {
print(tuple.0)
print(tuple.1)
}
This will print:
All our dreams can come true, if we have the courage to pursue them.
Walt Disney
The secret of getting ahead is getting started
Mark Twain

Swift 4 How do I write/read dictionaries to/from the document directory?

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 to read string from Text which saved in Documents Directory with Swift? [duplicate]

This question already has answers here:
Read and write a String from text file
(21 answers)
Closed 5 years ago.
I have a Test.txt file saved in Documents Directory of an app. There are several names saved one by one in each line in the Test.txt file, like this:
Tom
Jack
Jerry
Jennifer
Lynn
I would like to add these names to an array, like this:
var nameList = ["Tom", "Jack", "Jerry", "Jennifer", "Lynn"]
Is there any way to get it work?
I have the following codes, but it will consider the names as one string.
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let archiveURL = dir.appendingPathComponent("Test").appendingPathExtension("txt")
do {
try Data(textView.text.utf8).write(to: archiveURL)
}
catch {
print("error")
}
do {
namesPool = try! [String(contentsOf: archiveURL, encoding: .utf8)]
}
}
The above codes will get the following array:
var nameList = ["Tom\nJack\nJerry\nJennifer\nLynn\n"]
Any suggestions would be appreciated.
You are missing one last step, separate it using:
let namesTogether = try! String(contentsOf: archiveURL, encoding: .utf8)
namesPool = namesTogether.components(separatedBy: "\n")
Swift 4
// String with multiple names separated by end of line
let nameStr = try! String(contentsOf: archiveURL, encoding: .utf8)
// array of Substrings
let nameArray = nameStr.split(separator: "\n")
// first name as String
let name = String(nameArray[0])
More about handling strings:Strings Cheat Sheet

Type Issues When Writing a Nested dictionary to a plist (Swift)

I'm trying to write a dictionary with multiple layers of nesting to a progress list (plist) in Swift. However, for some reason one of the dictionaries is being treated as an array when I inspect the plist leading to a bunch of type issues in my project.
Here is the original nested dictionary:
I've attached a screenshot showing the plist structure and another showing the original data structure, I know you aren't meant to show photos of code but this text editor isn't formatting it properly and is mistreating the angle brackets
original data structure
screenshot showing plist
UPDATED
Ok I added one more key value pair at the topmost level and its being written to the dictionary correctly. The problem I'm having now is that I can write to the plist just fine but when I try to read from it all I get is nil.
func initializeProgress() {
let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
if let documents = directories.first {
if let urlDocuments = NSURL(string: documents) {
let urlProgress = urlDocuments.URLByAppendingPathComponent("progress.plist")
let progressDict = NSDictionary(dictionary: ["AP Biology": ["Misc": ["correct": 0, "incorrect": 0, "totalInSection": 0, "percentDone": 0],
"Basics": ["correct": 0, "incorrect": 0, "totalInSection": 0, "percentDone": 0],
"Essential Chemistry": ["correct": 0, "incorrect": 0, "totalInSection": 0, "percentDone": 0],
"Molecules of Life": ["correct": 0, "incorrect": 0, "totalInSection": 0, "percentDone": 0]]])
progressDict.writeToFile(urlProgress.path!, atomically: true)
}
}
}
func retrieveAndSetProgress() {
let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documents = directories.first
let urlDocuments = NSURL(string: documents!)
let urlProgress = urlDocuments!.URLByAppendingPathComponent("progress.plist")
print(NSDictionary(contentsOfURL: urlProgress))
let data = NSData(contentsOfURL: urlProgress, options: NSDataReadingOptions())
print(data)
progress = NSDictionary(contentsOfURL: urlProgress)! as! Dictionary<String, Dictionary<String, Dictionary<String, Int>>>
}
progress is a global variable and the last line of the second method produces an error: fatal error: unexpectedly found nil while unwrapping an Optional value
change
print(NSDictionary(contentsOfURL: urlProgress))
to
print(NSDictionary(contentsOfFile: urlProgress.absoluteString))
It can read it then. I just tested on a playground

Print all filenames in a folder in iOS application

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)
}

Resources