2016-01-08 32 views
0

我正在尋找一種快速優化的方式來修剪iOS上的日誌文件。我想指定我的日誌文件具有最大行數(例如10,000)。將新行添加到文本文件的末尾似乎相對簡單。但是,我還沒有找到在文件開頭修剪行的快速方法。這是我提出的(慢)代碼。快速修剪iOS上日誌文件開頭行的方法

guard let fileURL = self.fileURL else { 
     return 
    } 

    guard let path = fileURL.path else { 
     return 
    } 

    guard let fileHandle = NSFileHandle(forUpdatingAtPath: path) else { 
     return 
    } 

    fileHandle.seekToEndOfFile() 
    fileHandle.writeData(message.dataUsingEncoding(NSUTF8StringEncoding)!) 
    fileHandle.writeData("\n".dataUsingEncoding(NSUTF8StringEncoding)!) 

    currentLineCount += 1 

    // TODO: This could probably use some major optimization 
    if currentLineCount >= maxLineCount { 
     if let fileString = try? NSString(contentsOfURL: fileURL, encoding: NSUTF8StringEncoding) { 
      var lines = fileString.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) 
      lines.removeFirst() 
      let newData = lines.joinWithSeparator("\n") 
      fileHandle.seekToFileOffset(0) 
      fileHandle.writeData(newData.dataUsingEncoding(NSUTF8StringEncoding)!) 
     } 
    } 

    fileHandle.closeFile() 
+0

我敢肯定的是iOS的一些不錯的第三方記錄解決方案,但我正在尋找一個更明確的解決方案,我可以添加到我自己的自定義日誌代碼。 – JacobJ

+0

看看CocoaLumberJack的代碼。它已經做到了你想要的。 – rmaddy

+0

你確定嗎?看着CocoaLumberJack,我看到了滾動日誌文件的選項,但實際上並沒有看到它修剪日誌文件。 – JacobJ

回答

1

有你的問題的兩個方面。 首先,您的代碼從日誌文件中刪除單個 行。因此,一旦達到限制,每個新的日誌消息都會導致整個文件被讀取,縮短並重新寫入。

使用「高水位標誌」和「低水位標誌」會更有效。例如,如果您希望保留最後一行10.000行,則 會讓日誌文件增長,直到它具有15.000行,然後將它截斷爲 它爲10.000行。這大大減少了「修剪動作」 的數量。

部分是關於截斷本身。您的代碼會將 文件加載到NSString中,該文件要求將UTF-8數據 轉換爲Unicode字符 (並且如果日誌文件中存在單個無效字節則會失敗)。 然後將字符串拆分成一個數組,將其中一個數組元素刪除, 將數組連接到一個字符串,然後將 寫回到該文件,該文件將Unicode字符轉換爲UTF-8。

我沒有做過性能測試,但我可以想像,它可能是 更快地對二進制數據進行操作,而無需使用的轉換到 NSStringArray和背部。這裏是一個可能的實現 從文件開始刪除線的給定數量:

func removeLinesFromFile(fileURL: NSURL, numLines: Int) { 

    do { 
     let data = try NSData(contentsOfURL: fileURL, options: .DataReadingMappedIfSafe) 
     let nl = "\n".dataUsingEncoding(NSUTF8StringEncoding)! 

     var lineNo = 0 
     var pos = 0 
     while lineNo < numLines { 
      // Find next newline character: 
      let range = data.rangeOfData(nl, options: [], range: NSMakeRange(pos, data.length - pos)) 
      if range.location == NSNotFound { 
       return // File has less than `numLines` lines. 
      } 
      lineNo++ 
      pos = range.location + range.length 
     } 

     // Now `pos` is the position where line number `numLines` begins. 
     let trimmedData = data.subdataWithRange(NSMakeRange(pos, data.length - pos)) 
     trimmedData.writeToURL(fileURL, atomically: true) 

    } catch let error as NSError { 
     print(error.localizedDescription) 
    } 
} 
1

,而不是編寫新的生產線的日誌,事後處理的附加內容,做到既寫爲一步微調:

let fileString = (try? NSString(contentsOfURL: fileURL, encoding: NSUTF8StringEncoding)) as NSString? ?? "" 
var lines = fileString.characters.split("\n").map{String($0)} 
lines.append(message) 
// this also more generic as it will remove any number of extra lines 
lines.removeFirst(max(currentLineCount - maxLineCount), 0)) 
let newLogContents = lines.joinWithSeparator("\n") 
(newLogContents as NSString).writeToURL(fileURL, atomically: true, encoding: NSUTF8StringEncoding) 
+0

這對大文件來說是個壞主意。你不需要一次把整個文件存儲在內存中。 – rmaddy

+0

我同意你的觀點,但是如果提問者想要問題中提到的那種行爲,這是一條路。對於maxLineCount(甚至10000)的小值,考慮到我們沒有全部10k行2k長的課程,內存使用應該沒有問題:) – Cristik

0

我已經更新馬丁閱讀答題斯威夫特3,我也改變了它,這樣我們就可以通過數量線保持,而不是行數的刪除:

func removeLinesFromFile(fileURL: URL, linesToKeep numLines: Int) { 

    do { 
     let data = try Data(contentsOf: fileURL, options: .dataReadingMapped) 
     let nl = "\n".data(using: String.Encoding.utf8)! 

     var lineNo = 0 
     var pos = data.count-1 
     while lineNo <= numLines { 
      // Find next newline character: 
      guard let range = data.range(of: nl, options: [ .backwards ], in: 0..<pos) else { 
       return // File has less than `numLines` lines. 
      } 
      lineNo += 1 
      pos = range.lowerBound 
     } 

     let trimmedData = data.subdata(in: pos..<data.count) 
     try trimmedData.write(to: fileURL) 

    } catch let error as NSError { 
     print(error.localizedDescription) 
    } 
}