How do I use String(contentsOfFile: ) in Swift? [duplicate] - swift

This question already has answers here:
Read and write a String from text file
(21 answers)
Xcode 7.1 beta: Content Of File Error
(1 answer)
Closed 4 years ago.
Edit: I do not believe this question is a duplicate of Read and write a String from text file. I linked that exact question in this one explaining that it did not work!
I want to be able to read a .txt file I am including within my Xcode project in an iOS app. I have the following code:
let bundle = Bundle.main
override func sceneDidLoad() {
let path = bundle.path(forResource: "data", ofType: "txt")
let string = try String(contentsOfFile: path!) else throw Error
}
All the lines up until let string = ... are fine. However, everything I have found in questions such as this one are unable to read the data.txt file as they are incorrect/outdated syntax.
How do I read from it?
Edit: I've got the let string to be this:
do {
let string = try String(contentsOfFile: path!)
print(string) // prints the content of data.txt
}
catch {
throw Error
}
But I still have two errors:
Thrown expression type 'Error.Protocol' does not conform to 'Error'
and
Error is not handled because the enclosing function is not declared 'throws'
How do I fix the errors?

You need to handle the possible error thrown by encapsulating the throwable function in a do-catch block. In the catch block you shouldn't throw an error, but rather parse the error thrown and decide what to do with it.
let path = bundle.path(forResource: "data", ofType: "txt")!
do {
let string = try String(contentsOfFile: path)
} catch {
print(error)
// Handle the error
}

Related

Can you perform file I/O in a REPL on Repl.it when using Swift?

There's an online site here called Repl.it that gives you an in-browser REPL environment for a ton of languages. It's great to prove out code that you post here on SO. (I think you can even include it here actually but I wasn't successful in embedding mine.)
Anyway, when using Swift, I'm wondering if it's possible to perform file read/write persistence up there. I haven't found any articles that say yes, but I have found some that show them talking about how much storage you have, and it is supposed to be the full Swift runtime with all features, so I'm not sure.
This code fails however, saying it can't be performed.
import Foundation
let file = "file.txt" //this is the file. we will write to and read from it
let text = "some text" //just a text
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(file)
//writing
do {
try text.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {
print(error)
}
//reading
do {
let text2 = try String(contentsOf: fileURL, encoding: .utf8)
print("Read back in '\(text2)'")
}
catch {/* error handling here */}
}
else{
print("Couldn't get document directory")
}
You can open it here... Swift File Persistence REPL
I admit I'm 90% sure this isn't the right place for this, but since Repl.it does let you play with and execute Swift and this is a question about what Swift is needed to accomplish this, I figured I'd try!

How can I write to a file, line by line in Swift 4

I need help figuring out how to write repeatedly to the same, open, output file.
I am using Swift 4.2. My searches and tests have turned up only code that writes a single text string to a file and then closes the file. The next opening overwrites the last one. An example is shown below.
The problem is that I need to be able to write large numbers of records (say, 1.5 million) and perform calculations on each record just before it is written to a file. That’s not feasible when the code will only write once before closing. I'm calling this "writing line by line", much like the opposite, to "read line by line."
I tried to find an option in various Swift write statements and SO posts, but everything seems to be geared toward writing once then closing the file. I tried an open for append, but that did not work and anyway it seems inefficient to open, close, reopen-append each time I want to write to a file. I tried some C code in Swift, using open(… and freopen(… but could not get something that the compiler wouldn't complain about. Hopefully, there is a way to do this all in Swift. The following code works nicely for one write.
let file0 = “test_file.txt”
let s0 = ("This is a test line of text")
do {
try s0.write(to: NSURL(fileURLWithPath: file0) as URL, atomically: false, encoding: String.Encoding.utf8)
} catch {
print("Problem writing to file0")
}
How can I adapt this code snippet to write a string, and then another and another etc, and before closing the file when it’s all done? If not with this, is there Swift code that will do the job?
Following are the essential code components needed to write to a file, line-by-line in Swift. First is some file management code to create a file if it does not exist, then there is code to print a series of example statements, followed by code to print to the file in a loop, and finally close the file. This code worked correctly in Swift 4.2. The difference between this and the method in the question is that the write statements in this code use a method of fileHandle! and the question shows a method of a Swift string.
print("Swift_Write_to_File_Test_1")
var outFilename: NSString = "test_file.txt"
// Begin file manager segment
// Check for file presence and create it if it does not exist
let filemgr = FileManager.default
let path = filemgr.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).last?.appendingPathComponent(outFilename as String)
if !filemgr.fileExists(atPath: (path?.absoluteString)!) {
filemgr.createFile(atPath: String(outFilename), contents:Data(" ".utf8), attributes: nil)
}
// End file manager Segment
// Open outFilename for writing – this does not create a file
let fileHandle = FileHandle(forWritingAtPath: outFilename as String)
if(fileHandle == nil)
{
print("Open of outFilename forWritingAtPath: failed. \nCheck whether the file already exists. \nIt should already exist.\n");
exit(0)
}
var str: NSString = "2. Test string from NSString.\n";
var str0: String = "3. Test string from a Swift String.\n"
var str1: NSString = "4. Test string from NSString.\n";
fileHandle!.write("1. Text String in-line with code statement.\n".data(using: .utf8)!)
fileHandle!.write(String(str).data(using: .utf8)!)
fileHandle!.write(str0.data(using: .utf8)!)
fileHandle!.write(String(str1).data(using: .utf8)!)
fileHandle!.write("5. Text String in-line with code statement.\n".data(using: .utf8)!)
fileHandle!.write("6. Text in a loop follows: \n".data(using: .utf8)!)
for i in 0...5
{
//Assemble a string then write it to the file.
var s0: String = ""
s0 = String(i)
//s0.append(" ... some text here.\n") // See improvement below
s0 += " ... some text here.\n" // This is a better than .append
fileHandle!.write(s0.data(using: .utf8)!)
}
// End of file-writing segment
fileHandle!.closeFile()
This worked for me in Swift 5:
func writeFile() -> Bool
{
let outFilename: String = "test_file.txt"
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let outFilePath = documentsURL!.appendingPathComponent(outFilename).path
let fileManager = FileManager.default
// If file exists, remove it
if fileManager.fileExists(atPath: outFilePath)
{
do { try fileManager.removeItem(atPath: outFilePath) }
catch { return false }
}
// Create file and open it for writing
fileManager.createFile(atPath: outFilePath, contents:Data(" ".utf8), attributes: nil)
let fileHandle = FileHandle(forWritingAtPath: outFilePath)
if fileHandle == nil
{
return false
}
else
{
// Write data
fileHandle!.write("Test line 1\n".data(using: .utf8)!)
fileHandle!.write("Test line 2\n".data(using: .utf8)!)
fileHandle!.write("Test line 3\n".data(using: .utf8)!)
// Close file
fileHandle!.closeFile()
return true
}
}

The file “xxx” couldn’t be opened because there is no such file [duplicate]

This question already has answers here:
UIImage(contentsOfFile:) returning nil despite file existing in caches directory [duplicate]
(1 answer)
NSFileManager.defaultManager().fileExistsAtPath returns false instead of true
(2 answers)
Closed 5 years ago.
I would like to open a .txt file and save the content as a String.
I tried this:
let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("xxx.txt")
var contentString = try String(contentsOfFile: path.absoluteString)
print(path)
The print result:
file:///Users/Username/Documents/xxx.txt
But I get the error:
The file “xxx.txt” couldn’t be opened because there is no such file
The file is 100% available
Notice: I working with swift 4 for macOS
Your path variable is an URL, and path.absoluteString returns
a string representation of the URL (in your case the string
"file:///Users/Username/Documents/xxx.txt"), not the underlying file path
"/Users/Username/Documents/xxx.txt".
Using path.path is a possible solution:
let path = ... // some URL
let contentString = try String(contentsOfFile: path.path)
but the better method is to avoid the conversion and use the URL-based
methods:
let path = ... // some URL
let contentString = try String(contentsOf: path)
thx, I solved my problem.
I have to use .path instead of .absoluteString:
var contentString = try String(contentsOfFile: path.path)

Write to file not working (Swift 4)

I am starting learning about Swift programming. Up to now, I have already developed my first working app. Although simple, it is a very useful one. But with the introduction of Swift 4 and XCode 9, I'm facing some headaches. Right now I am trying to write a small piece of code to write a string to a file, like this:
let fileName = "myFile.txt"
let path = NSURL(fileURLWithPath:
NSTemporaryDirectory()).appendingPathComponent(fileName)
var myText = "Some text to write to file"
do {
try myText.write(to: path!, atomically: true, encoding: UTF8)
} catch {
// Handle error
}
When I write myText.write, XCode suggests the above syntax, but right after I choose it and fill the placeholders, XCode displays the error "Extra argument 'atomically' in call. Note that it is the very structure it suggested. I haven't found any workaround until now. Can anyone help me?
The error is misleading. The encoding parameter is wrong
try myText.write(to: path!, atomically: true, encoding: .utf8)
And don't use NSURL in Swift 3+, use native URL:
let url = URL(fileURLWithPath: ...
However I recommend this way
let fileName = "myFile.txt"
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
let myText = "Some text to write to file"
let data = Data(myText.utf8)
do {
try data.write(to: url, options: .atomic)
} catch {
print(error)
}

Swift3.0 fileAttributes throws "no such file" error on existing file [duplicate]

This question already has an answer here:
Swift: Reading a plist from MainBundle and writing directly to Documents fails
(1 answer)
Closed 6 years ago.
I am quite new to Swift and I am trying to implement a file creation date check.
The idea is to check if the file was created longer than 7 days ago. For some reason the code always returns "no such file" error.
To check what is wrong i used the same path to read the contents of the file in the same function and that works flawlessly.
Am I using the path incorrectly or have I misunderstood something?
func creationDateCheck(name: String) -> Bool {
// This is the path I am using, file is in the favorites folder in the .documentsDirectory
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let myFilesPath = documentsUrl.appendingPathComponent("favorites/" + name + ".xml")
let pathString = "\(myFilesPath)"
//First do block tries to get the file attributes and fails
do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: pathString)
print(fileAttributes)
let creationDate = (fileAttributes[FileAttributeKey.creationDate] as? NSDate)!
return daysBetweenDates(endDate: creationDate as Date) > 7
} catch let error as NSError {
print(error.localizedDescription)
}
// Second do block reads from file successfully using the same path
do {
print(try String(contentsOf: myFilesPath, encoding: String.Encoding.utf8))
}catch {print("***** ERROR READING FROM FILE *****")}
return false
}
You can not get String from URL directly using "\(myFilesPath)" instead of that you need to use path property of URL.
let fileAttributes = try FileManager.default.attributesOfItem(atPath: myFilesPath.path)
The reason you are reading content of file successfully is that you have used String(contentsOf:encoding:) and it will accept URL object as first parameter.