How to add text into a .csv data in Swift? - ios

I want to add some text like "Hi;Test;Pen" into my .csv file.
I have used the CSVImporter to insert the text of the .csv into my Xcode project. Here is the code, I have used for it:
guard let VokabelPath = Bundle.main.path(forResource: ResourceExample, ofType:"csv") else {
debugPrint(ResourceExample + " not found")
return
}
let importer = CSVImporter<[String]>(path: VokabelPath, delimiter: ";")
let importedRecords = importer.importRecords { $0 }
for record in importedRecords {
self.Vokabeln.insert(record, at: self.Vokabelzähler)
self.Vokabelzähler += 1
}
But for some reasons I want to
add something to the file
Change something in the file (e.g. in Line 4)
Delete the text in the file (e.g. filetext = ""
I have tried to use this Tutorial and I have made this code:
let fileName = "Tasks.csv"
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
var csvText = "Test;Example;Apple;Pen\n"
do {
try csvText.write(to: path!, atomically: true, encoding: String.Encoding.utf8)
} catch {
print("Failed to create file")
print("\(error)")
}
guard let VokabelPath = Bundle.main.path(forResource: "Tasks", ofType:"csv") else {
debugPrint("Tasks not found")
return
}
let importer = CSVImporter<[String]>(path: VokabelPath, delimiter: ";")
let importedRecords = importer.importRecords { $0 }
for record in importedRecords {
self.Vokabeln.insert(record, at: self.Vokabelzähler)
self.Vokabelzähler += 1
print(record)
}
but he prints only "Tasks not found". What is my mistake?
I hope you can help me,
Thank you.
EDIT:
The person who made the first answer has written, I can't save files in the bundle.
He has written to me I should use NSSearchPathForDirectoriesInDomainsso I have updated my code and this works:
let DownloadPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let VokabelPath = DownloadPath.appendingPathComponent("Tasks.csv")
let InhaltData = Inhalt.data(using: .utf8)
print(VokabelPath)
FileManager.default.createFile(atPath: VokabelPath, contents: InhaltData, attributes: nil)
let importer = CSVImporter<[String]>(path: VokabelPath, delimiter: ";")
let importedRecords = importer.importRecords { $0 }
for record in importedRecords {
self.Vokabeln.insert(record, at: self.Vokabelzähler)
self.Vokabelzähler += 1
}
But I have one further question:
I hav some datas in my Xcode project and I can get them with Bundle.main. But I want to use only one function, so is it possible, to get them with NSSearchPathForDirectoriesInDomainstoo?

In order to change a file, you would need to import the data in, make the necessary changes to the data and then write the data back to the same file, overwriting the previous content. That is how you would make changes generally - you don't make changes directly to the file.
Does that make sense?
If it does, then you could easily modify the tutorial you pointed to (the one for creating and exporting CSV) and write back the data that you read from the original file after you make the modifications.
As for your question about not wanting to use a library, you can always write your own CSV parser. It is not very difficult since all you have to do is read the text from the file a line at a time and then separate out the values by comma. A simple parser is straightforward but allowing for more complicated cases could take a bit more effort. It would all depend on your use-cases and the type of data you'd be handling. The easiest way still would be to use your importing library and then output via custom code.
Regarding your additional questions, if the following code fails:
guard let VokabelPath = Bundle.main.path(forResource: "Tasks", ofType:"csv") else {
debugPrint("Tasks not found")
return
}
Then there is either an issue with the file name (or extension) or you have not included the file as part of your Resources. The above code simply gets the path for a given file in your Resources.
The above code is different from what I was talking about with regards to NSSearchPathForDirectoriesInDomains - that was for writing a file from your app. What I meant was that you could not write a file back to your Resources - instead, you would have to write the modified file to your Documents folder. Hope that clarifies things :)

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

How can I create a csv file with sensors data in swift 5?

I have 3 labels inside my view, and this is how I get sensor data and write it inside labels:
func myDeviceMotion(){
print("Start DeviceMotion")
motion.deviceMotionUpdateInterval = 0.5
motion.startDeviceMotionUpdates(to: OperationQueue.current!) {
(data, error) in
print(data as Any)
if let trueData = data {
self.view.reloadInputViews()
self.xDevi!.text = "x (pitch): \(trueData.attitude.pitch)"
self.yDevi!.text = "y (roll): \(trueData.attitude.roll)"
self.zDevi!.text = "z (yaw): \(trueData.attitude.yaw)"
}
}
return
}
Now I would like to save that date inside a csv file. How can I do that?
I have already tried the solution proposed inside this answer: How to log sensor data and export to CSV?, but it doesn't work for me.
// Open a new file for writing using FileManager (may have to remove an old one)
let fh: FileHandle = ... // open the file
// Header first (optional)
var s = "Pitch,Roll,Yaw\n" // note no spaces, comma is the operator
fh.writeData(s.data(using: .utf))
// then for each line of dat
s = String(format: "%f,%f,%f\n", trueData.attitude.pitch, trueData.attitude.roll, trueData.attitude.yaw)
fh.writeData(s.data(using: .utf))
// when done, close the file using fh.closefile()

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

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