2014-12-06 31 views
21

ho già letto Read and write data from text fileaggiungere testo o dati in file di testo a Swift

ho bisogno di aggiungere i dati (una stringa) alla fine del mio file di testo.
Un modo ovvio per farlo è leggere il file dal disco e aggiungere la stringa alla fine di esso e scriverlo di nuovo, ma non è efficiente, specialmente se si hanno a che fare con file di grandi dimensioni e spesso in esecuzione.

Quindi la domanda è "Come aggiungere una stringa alla fine di un file di testo, senza leggere il file e scrivere tutto indietro"?

Finora ho:

let dir:NSURL = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.CachesDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last as NSURL 
    let fileurl = dir.URLByAppendingPathComponent("log.txt") 
    var err:NSError? 
    // until we find a way to append stuff to files 
    if let current_content_of_file = NSString(contentsOfURL: fileurl, encoding: NSUTF8StringEncoding, error: &err) { 
     "\(current_content_of_file)\n\(NSDate()) -> \(object)".writeToURL(fileurl, atomically: true, encoding: NSUTF8StringEncoding, error: &err) 
    }else { 
     "\(NSDate()) -> \(object)".writeToURL(fileurl, atomically: true, encoding: NSUTF8StringEncoding, error: &err) 
    } 
    if err != nil{ 
     println("CANNOT LOG: \(err)") 
    } 
+0

difficile trovare questo senza usare la parola memoria: D;) – John

risposta

27

si dovrebbe usare NSFileHandle, può seek to the end of the file

let dir:NSURL = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.CachesDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last as NSURL 
let fileurl = dir.URLByAppendingPathComponent("log.txt") 

let string = "\(NSDate())\n" 
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! 

if NSFileManager.defaultManager().fileExistsAtPath(fileurl.path!) { 
    var err:NSError? 
    if let fileHandle = NSFileHandle(forWritingToURL: fileurl, error: &err) { 
     fileHandle.seekToEndOfFile() 
     fileHandle.writeData(data) 
     fileHandle.closeFile() 
    } 
    else { 
     println("Can't open fileHandle \(err)") 
    } 
} 
else { 
    var err:NSError? 
    if !data.writeToURL(fileurl, options: .DataWritingAtomic, error: &err) { 
     println("Can't write \(err)") 
    } 
} 
+3

Puoi provare una versione 3 veloce di questo codice? –

+10

Sareste stupiti di quanto sia facile convertire questo in swift 3 se si fa clic su quei piccoli cerchi rossi con i punti bianchi in Xcode. – Chris

13

Ecco una versione per Swift 2, utilizzando i metodi di estensione su stringa e NSData.

//: Playground - noun: a place where people can play 

import UIKit 

extension String { 
    func appendLineToURL(fileURL: NSURL) throws { 
     try self.stringByAppendingString("\n").appendToURL(fileURL) 
    } 

    func appendToURL(fileURL: NSURL) throws { 
     let data = self.dataUsingEncoding(NSUTF8StringEncoding)! 
     try data.appendToURL(fileURL) 
    } 
} 

extension NSData { 
    func appendToURL(fileURL: NSURL) throws { 
     if let fileHandle = try? NSFileHandle(forWritingToURL: fileURL) { 
      defer { 
       fileHandle.closeFile() 
      } 
      fileHandle.seekToEndOfFile() 
      fileHandle.writeData(self) 
     } 
     else { 
      try writeToURL(fileURL, options: .DataWritingAtomic) 
     } 
    } 
} 

// Test 
do { 
    let url = NSURL(fileURLWithPath: "test.log") 
    try "Test \(NSDate())".appendLineToURL(url) 
    let result = try String(contentsOfURL: url) 
} 
catch { 
    print("Could not write to file") 
} 
+0

non è necessario importare UIKit, no? –

22

Ecco un aggiornamento per la risposta di PointZeroTwo a Swift 3.0, con una breve nota - nella sperimentazione parco giochi mediante una funzione semplice opere filepath, ma nella mia app reale ho bisogno di costruire l'URL utilizzando .documentDirectory (o che mai directory si è scelto di utilizzare per la lettura e la scrittura - assicurarsi che sia coerente in tutta la vostra applicazione):

extension String { 
    func appendLineToURL(fileURL: URL) throws { 
     try (self + "\n").appendToURL(fileURL: fileURL) 
    } 

    func appendToURL(fileURL: URL) throws { 
     let data = self.data(using: String.Encoding.utf8)! 
     try data.append(fileURL: fileURL) 
    } 
} 

extension Data { 
    func append(fileURL: URL) throws { 
     if let fileHandle = FileHandle(forWritingAtPath: fileURL.path) { 
      defer { 
       fileHandle.closeFile() 
      } 
      fileHandle.seekToEndOfFile() 
      fileHandle.write(self) 
     } 
     else { 
      try write(to: fileURL, options: .atomic) 
     } 
    } 
} 
//test 
do { 
    let dir: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last! as URL 
    let url = dir.appendingPathComponent("logFile.txt") 
    try "Test \(Date())".appendLineToURL(fileURL: url as URL) 
    let result = try String(contentsOf: url as URL, encoding: String.Encoding.utf8) 
} 
catch { 
    print("Could not write to file") 
} 

Grazie PointZeroTwo.

Problemi correlati