Добавить текст или данные в текстовый файл в 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)")
}
Ответы
Ответ 1
Вы должны использовать NSFileHandle, он может искать в конце файла
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)")
}
}
Ответ 2
Здесь обновление для ответа PointZeroTwo в Swift 3.0 с одной быстрой записью - в тестировании игровой площадки с использованием простой файловой политики, но в моем фактическом приложении мне нужно было создать 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.
Ответ 3
Здесь версия для Swift 2, используя методы расширения для String и 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")
}
Ответ 4
Чтобы остаться в духе PointZero Two. Здесь обновлен его код для 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)
}
}
}
Ответ 5
Обновление: я написал сообщение в блоге об этом, которое вы можете найти здесь !
Сохранение вещей Swifty, вот пример использования протокола FileWriter
с реализацией по умолчанию (Swift 4.1 на момент написания этой статьи):
- Чтобы использовать это, пусть ваш объект (класс, структура, перечисление) соответствует этому протоколу и вызовет функцию записи (fyi, it throws!).
- Записывает каталог документов.
- Будет добавлен в текстовый файл, если файл существует.
- Создает новый файл, если текстовый файл не существует.
-
Примечание: это только текст. Вы можете сделать что-то похожее на запись/добавление 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)
}
}
}
Ответ 6
Вот способ обновления файла гораздо более эффективным способом.
let monkeyLine = "\nAdding a 🐵 to the end of the file via FileHandle"
if let fileUpdater = try? FileHandle(forUpdating: newFileUrl) {
// function which when called will cause all updates to start from end of the file
fileUpdater.seekToEndOfFile()
// which lets the caller move editing to any position within the file by supplying an offset
fileUpdater.write(monkeyLine.data(using: .utf8)!)
//Once we convert our new content to data and write it, we close the file and thats it!
fileUpdater.closeFile()
}