Ajouter du texte ou des données au fichier texte de Swift

j'ai déjà lu lire et écrire des données à partir du fichier texte

je dois ajouter les données (une chaîne) à la fin de mon fichier texte.

Une façon évidente de le faire est de lire le fichier à partir du disque et d'ajouter la chaîne à la fin de celui-ci et de l'écrire en retour, mais ce n'est pas efficace, surtout si vous avez affaire à de grands fichiers et le faire souvent.

donc la question est " comment ajouter une chaîne jusqu'à la fin d'un fichier texte, sans lire le fichier et écrire tout"?

jusqu'à présent j'ai:

    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)")
    }
25
demandé sur Community 2014-12-06 03:56:44

5 réponses

vous devez utiliser NSFileHandle, il peut chercher à la fin du fichier

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)")
    }
}
28
répondu Matthias Bauch 2014-12-06 01:45:45

Voici une mise à jour pour la réponse de PointZeroTwo dans Swift 3.0, avec une note rapide - dans le terrain de jeu de test à l'aide d'un simple filepath fonctionne, mais dans mon application actuelle, j'ai dû construire L'URL en utilisant .documentDirectory (ou le répertoire que vous avez choisi d'utiliser pour lire et écrire - assurez-vous qu'il est cohérent dans toute votre application):

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

Merci PointZeroTwo.

26
répondu davidrynn 2016-11-21 19:37:01

Voici une version pour Swift 2, en utilisant des méthodes d'extension sur la chaîne de caractères et 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")
}
14
répondu PointZeroTwo 2015-09-25 17:23:44

mise à Jour: j'ai écrit un billet de blog sur ce que vous pouvez trouver ici !

Keeping things Swifty , voici un exemple d'utilisation d'un protocole FileWriter avec implémentation par défaut (Swift 4.1 au moment de la rédaction):

  • pour utiliser ceci, faites que votre entité (class, struct, enum) se conforme à ce protocole et appelez la fonction write (pour info, il lance!).
  • écrit dans le répertoire des documents.
  • ajouter le fichier texte si le fichier existe.
  • Va créer un nouveau fichier si le fichier texte n'existe pas.
  • Note: Ceci est uniquement pour le texte. Vous pourriez faire quelque chose de similaire à écrire/ajouter Data .

    import Foundation
    
    enum FileWriteError: Error {
        case directoryDoesntExist
        case convertToDataIssue
    }
    
    protocol FileWriter {
        var fileName: String { get }
        func write(_ text: String) throws
    }
    
    extension FileWriter {
        var fileName: String { return "File.txt" }
    
        func write(_ text: String) throws {
            guard let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
                throw FileWriteError.directoryDoesntExist
            }
    
            let encoding = String.Encoding.utf8
    
            guard let data = text.data(using: encoding) else {
                throw FileWriteError.convertToDataIssue
            }
    
            let fileUrl = dir.appendingPathComponent(fileName)
    
            if let fileHandle = FileHandle(forWritingAtPath: fileUrl.path) {
                fileHandle.seekToEndOfFile()
                fileHandle.write(data)
            } else {
                try text.write(to: fileUrl, atomically: false, encoding: encoding)
            }
        }
    }
    
1
répondu jason z 2018-05-16 19:38:51

pour rester dans L'esprit PointZero deux. Voici une mise à jour de son code Swift 4.1

extension String {
    func appendLine(to url: URL) throws {
        try self.appending("\n").append(to: url)
    }
    func append(to url: URL) throws {
        let data = self.data(using: String.Encoding.utf8)
        try data?.append(to: url)
    }
}

extension Data {
    func append(to url: URL) throws {
        if let fileHandle = try? FileHandle(forWritingTo: url) {
            defer {
                fileHandle.closeFile()
            }
            fileHandle.seekToEndOfFile()
            fileHandle.write(self)
        } else {
            try write(to: url)
        }
    }
}
1
répondu Luc-Olivier 2018-05-23 21:49:32