主頁(yè) > 知識(shí)庫(kù) > golang實(shí)戰(zhàn)之truncate日志文件詳解

golang實(shí)戰(zhàn)之truncate日志文件詳解

熱門標(biāo)簽:汕頭小型外呼系統(tǒng) 濱州自動(dòng)電銷機(jī)器人排名 釘釘有地圖標(biāo)注功能嗎 黃岡人工智能電銷機(jī)器人哪個(gè)好 浙江高頻外呼系統(tǒng)多少錢一個(gè)月 阿里云ai電話機(jī)器人 建造者2地圖標(biāo)注 惠州電銷防封電話卡 鄭州亮點(diǎn)科技用的什么外呼系統(tǒng)

前言

有時(shí)候我們生成的日志文件很大,如果文件過(guò)大,或者磁盤空間有限,那么我們就需要把日志文件改小一點(diǎn)。

(當(dāng)然實(shí)際應(yīng)用場(chǎng)景中,一般采用log rotate的方式實(shí)現(xiàn)多個(gè)日志文件,定期把舊的日志文件挪走或者刪除)

現(xiàn)在我們考慮如何把日志文件變小的場(chǎng)景。

首先想到的是文件truncate,遺憾的是truncate是把新的內(nèi)容刪掉,而不是把舊的內(nèi)容刪掉;因?yàn)橥ǔN覀兊淖龇ㄊ且雅f的日志內(nèi)容刪除,而保留最新的日志內(nèi)容。

方法1:拷貝文件,然后把前半部分刪除,保留新的后半部分

$ wc -l logfile
$ tail -n {LINENUM}/2 logfile > logfile2
$ mv logfile2 logfile

缺點(diǎn)是需要額外的臨時(shí)磁盤空間(logfile2),保留新拷貝的文件

方法2:把日志文件讀入內(nèi)存,截去前半部分,把后半部分重新寫(xiě)會(huì)文件。

缺點(diǎn)也是要?jiǎng)?chuàng)建一個(gè)臨時(shí)文件,或者把整個(gè)文件內(nèi)容一次性讀入內(nèi)存。

下面是一個(gè)實(shí)現(xiàn)創(chuàng)建臨時(shí)文件的例子:

(如果采用整個(gè)文件讀入內(nèi)存,那么可以重復(fù)覆蓋使用原來(lái)的讀入文件,不用創(chuàng)建臨時(shí)文件):

package main

import (
 "bufio"
 "log"
 "io"
 "os"
)

func ReadLine(r *bufio.Reader, w *bufio.Writer) error {
 for i := 0; ; i++ {
  line, err := r.ReadString('\n')
  if i >= 12554364/2 { // this number is hard-codes just for example use
   if _,err := w.WriteString(line); err != nil {
    log.Fatal(err)
   }
  }

  if err != nil {
   if err == io.EOF {
    return nil
   }
   return err
  }
 }
 return nil
}

func main() {
 fin, err := os.Open("data.in")
 if err != nil {
  log.Fatal(err)
 }
 defer fin.Close()

 fout, err := os.Create("data.dat")
 if err != nil {
  log.Fatal(err)
 }
 defer fout.Close()

 reader := bufio.NewReader(fin)
 writer := bufio.NewWriter(fout)
 if err := ReadLine(reader, writer); err != nil {
  log.Fatal(err)
 }
 writer.Flush()
}

運(yùn)行:

對(duì)于1G大小的日志文件,在我的Linux上執(zhí)行時(shí)間大約是:

$ go build  time ./main
real 0m6.972s
user 0m4.668s
sys  0m2.055s

方法3:也是利用文件,把文件mmap映射到內(nèi)存,然后使用copy函數(shù)覆蓋內(nèi)存。

缺點(diǎn)是,mmap操作日志文件不能過(guò)大。

下面是一個(gè)實(shí)現(xiàn)的代碼例子:

package main

import (
 "fmt"
 "log"
 "os"
 "syscall"
)

// Truncate file to half size, with line aligned.
func truncateText(f *os.File) error {
 fi, err := f.Stat()
 if err != nil {
  return err
 }

 mem, err := syscall.Mmap(int(f.Fd()), 0, int(fi.Size()), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
 if err != nil {
  return err
 }

 size := fi.Size()
 if size = 1 {
  // Don't need to truncate file if it's too small
  return nil
 }

 trun := size/2 - 1
 for ; trun  fi.Size(); trun ++ {
  if mem[trun] == '\n' {
   break
  }
 }

 //fmt.Printf("size=%d, trun=%d\n", size, trun)
 if trun >= size - 1 {
  trun = size/2
 } else {
  trun = trun + 1
 }

 // Overwrite file content
 copy(mem[0:], mem[trun:])
 
 err = syscall.Munmap(mem)
 if err != nil {
  return err
 }

 // truncate file
 f.Truncate(fi.Size() - trun)

 // reset file offset
 f.Seek(trun,0)

 return nil
}


func main() {
 path := "data.dat"

 f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0644)
 if err != nil {
  fmt.Println("Cannot create file")
  log.Fatal(err)
 }

 err = truncateText(f)
 if err != nil {
  fmt.Println("Cannot truncateLog file")
  log.Fatal(err)
 }

 f.Write([]byte("ABCD"))
 f.Close()
}

函數(shù)truncateText的功能就是把文件截取到原來(lái)的一半大小,并保持按行對(duì)齊;分如下幾步:

  • 先把文件映射syscall.Mmap 到內(nèi)存。
  • 查找到中間行的位置。
  • 然后用內(nèi)置函數(shù)copy,把中間行以后的挪動(dòng)到文件開(kāi)始位置。
  • 修改文件的大小file.Truncate
  • 重置文件的偏移指針offset
  • 取消文件映射syscall.Munmap

運(yùn)行:

對(duì)于1G大小的日志文件,在我的Linux上執(zhí)行時(shí)間大約是:

$ go build  time ./main
real 0m1.861s
user 0m0.335s
sys  0m0.650s

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

您可能感興趣的文章:
  • Oracle給用戶授權(quán)truncatetable的實(shí)現(xiàn)方案
  • delete from 表名與truncate table 表名區(qū)別
  • SQL中Truncate的用法
  • tf.truncated_normal與tf.random_normal的詳細(xì)用法
  • smarty中改進(jìn)truncate使其支持中文的方法
  • SQL Server中TRUNCATE事務(wù)回滾操作方法
  • 實(shí)例理解SQL中truncate和delete的區(qū)別
  • 詳解SQL中drop、delete和truncate的異同
  • Mysql開(kāi)啟慢SQL并分析原因
  • Truncate Table的用法講解

標(biāo)簽:泰安 瀘州 阿壩 滄州 昭通 東營(yíng) 晉中 駐馬店

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《golang實(shí)戰(zhàn)之truncate日志文件詳解》,本文關(guān)鍵詞  golang,實(shí)戰(zhàn),之,truncate,日志,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《golang實(shí)戰(zhàn)之truncate日志文件詳解》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于golang實(shí)戰(zhàn)之truncate日志文件詳解的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章