1

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?

  • Duplicate of https://stackoverflow.com/questions/27327067/append-text-or-data-to-text-file-in-swift ? – matt Sep 26 '19 at 00:27
  • As I see it, that one is the "append" problem. Open, append, close, etc. Seems inefficient compared to open, write, write, write, close, and methods that are available in C++. – CodeSmith28 Sep 26 '19 at 00:37
  • 1
    I don't quite see why. Where did the "close" come from? Once you have a file handle you can just leave it open: calculate, write, calculate, write, calculate, write...? – matt Sep 26 '19 at 01:04
  • I don't see it either, but when I tested it, and others like it in loops, I only get the last write. – CodeSmith28 Sep 26 '19 at 01:50
  • Duplicate of https://stackoverflow.com/questions/26989493/how-to-open-file-and-append-a-string-in-it-swift ? – matt Sep 26 '19 at 01:53
  • Possible a duplicate of https://stackoverflow.com/questions/38697950/an-efficient-way-of-writing-to-file-swift – Cristik Sep 26 '19 at 05:57
  • Looking at 38697950, taking the first set of code, checked as the answer, and adding an output path that is known to work, and modifying "max length:" to 2000, I get a "write failure" error. I'll check it further, today. – CodeSmith28 Sep 26 '19 at 12:15
  • My previous comment should refer to 26989493 instead of 38697950. I will check both responses further, today. – CodeSmith28 Sep 26 '19 at 12:59
  • Upon review, I see that 38697950 is an extract from another answer, and that other answer has comments that state that it doesn't work. So, to me, this question is not a duplicate, or at least the hoped-for response would not be a duplicate. – CodeSmith28 Sep 26 '19 at 14:18
  • @CodeSmith28 surely you can extract the needed information from those questions, even if it's distributed among multiple answers. Seems you expect a custom solution tailored for your specific task, however this is not what we do here, SO is not a coding service. – Cristik Sep 26 '19 at 19:56
  • I don't know about others, but for me, it's all about trying to learn the Swift syntax and after a week of digging through the documentation and several hundred searches of every combination I can think of, I got to the point where it would be helpful to know how a more knowledgable person might address the problem in Swift. That's why the desire to see some working code. I'm still working on it, and may yet find a solution. If I do, I'll post some working code. – CodeSmith28 Sep 27 '19 at 02:24

2 Answers2

1

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()
0

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
    }
}
Anthony.
  • 643
  • 7
  • 14