2014-12-06 2 views
21

я уже прочитал Read and write data from text fileAppend текст или данные в текстовый файл в Swift

Мне нужно добавить данные (строка) к концу моего текстового файла.
Один из очевидных способов сделать это - прочитать файл с диска и добавить строку до конца и записать ее, но она неэффективна, особенно если вы имеете дело с большими файлами и делаете это часто.

Итак, вопрос: «Как добавить строку в конец текстового файла, не читая файл и не записывая все это»?

до сих пор у меня есть:

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

сложно найти этот без использования памяти слов: D;) – John

ответ

27

Вы должны использовать NSFileHandle, он может 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

Можете ли вы оформить быструю 3-ю версию этого кода? –

+10

Вы были бы поражены тем, насколько легко преобразовать это в быстрое 3, если вы просто нажмете на эти маленькие красные круги с белыми точками в Xcode. – Chris

13

Вот версия для Swift 2, используя методы расширения на струнных и 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

не нужно импортировать UIKit, нет? –

22

Вот обновление для ответа PointZeroTwo в Swift 3.0, с одной быстрой нотой - в тестировании игровых площадок с использованием простого Filepath работ, но в моем фактическом приложении мне нужно, чтобы построить URL с помощью .documentDirectory (или какое-либо каталог, который вы решили использовать для чтения и записи - убедитесь, что он соответствует в течение вашего приложения):

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

спасибо PointZeroTwo.