duangou2028 2018-02-14 18:47
浏览 53

在应用程序中追加文件且不覆盖

I have a short GO app that I built to modify config files and had expected them to overwrite, but instead they are appending and I'm not sure why. I've tried os.Truncate() prior to my file.Sync() but end up with a malformed file. I've also attempted to write to a tmpfile, but end up with index errors and feel this is not worth the attempt. I expect the file to open, read in, modify and overwrite the existing content. It also looks as though the file is not completing to write? Maybe the buffer? What am I doing wrong?

App

package main

import (
  "strings"
  "bufio"
  "fmt"
  "regexp"
  "flag"
  "os"
  "io"
  "bytes"
)

var (
  filename  string
)

func isCommentOrBlank(line string) bool {
  return strings.HasPrefix(line, "#") || "" == strings.TrimSpace(line)
}

func fileExists(filename string) bool {
  if _, err := os.Stat(filename); err == nil {
    return true
  }
  return false
}

func limitLength(s string, length int) string {
  if len(s) < length {
    return s
  }
  return s[:length]
}

func padWithSpace(str, pad string, length int) string {
    for {
        str += pad
        if len(str) > length {
            return str[0:length]
        }
    }
}

func ingest(filename string) (err error) {
  file, err := os.OpenFile(filename, os.O_RDWR, 0644)
  defer file.Close()

  if err != nil {
    return err
  }

  reader := bufio.NewReader(file) // Start reading from the file with a reader.

  for {
    var buffer bytes.Buffer
    var l []byte
    var isPrefix bool

    for {
      l, isPrefix, err = reader.ReadLine()
      buffer.Write(l)
      if !isPrefix {
        break
      }
    }

    if err == io.EOF || err != nil {
      break
    }

    line    := buffer.String()
    pattern := regexp.MustCompile(`^#([^=]+)=(.+)$`)
    matches := pattern.FindAllStringSubmatch(line, -1) // matches is [][]string

    for _, string := range matches {
      n := strings.Replace(strings.TrimSpace(string[1]), "#", "", -1)
      v := strings.TrimSpace(string[2])
      e := strings.ToLower(strings.Replace(n, ".", "/", -1))

      // newline creation for if block
      nl := "{{if exists \"/" + e + "\" -}}
"
      nl += padWithSpace(n, " ", 80) + "= {{getv \"/" + e + "\" \"" + v + "\"}}
"
      nl += "{{end -}}
"
      file.WriteString(nl)
    }

    // dont proccess comments
    if (isCommentOrBlank(line)) {
      if (!strings.Contains(line, "=")) {
        file.WriteString(line + "
")
      }
    } else {
      a := strings.Split(line, "=")
      n := strings.TrimSpace(a[0])
      v := strings.TrimSpace(a[1])
      e := strings.ToLower(strings.Replace(n, ".", "/", -1))
      file.WriteString(padWithSpace(n, " ", 80) + "= {{getv \"/" + e + "\" \"" + v + "\"}}
")
    }
  }

  file.Sync()

  if err != io.EOF {
    fmt.Printf(" > Failed!: %v
", err)
  }
  return
}

func main() {
  flag.StringVar(&filename, "f", "filename", "The file location to be parsed")
  flag.Parse()

  if !fileExists(filename) {
    fmt.Println(" > File does not exist
")
  }

  ingest(filename)
}

Config to rewrite

# The file contains the properties for Chaos Monkey.
# see documentation at:
# https://github.com/Netflix/SimianArmy/wiki/Configuration

# let chaos run
simianarmy.chaos.enabled = true

# don't allow chaos to kill (ie dryrun mode)
simianarmy.chaos.leashed = true

# set to "false" for Opt-In behavior, "true" for Opt-Out behavior
simianarmy.chaos.ASG.enabled = false

# uncomment this line to use tunable aggression
#simianarmy.client.chaos.class = com.netflix.simianarmy.tunable.TunablyAggressiveChaosMonkey

# default probability for all ASGs
simianarmy.chaos.ASG.probability = 1.0

# increase or decrease the termination limit
simianarmy.chaos.ASG.maxTerminationsPerDay = 1.0

# Strategies
simianarmy.chaos.shutdowninstance.enabled = true
simianarmy.chaos.blockallnetworktraffic.enabled = false
simianarmy.chaos.burncpu.enabled = false
simianarmy.chaos.killprocesses.enabled = false
simianarmy.chaos.nullroute.enabled = false
simianarmy.chaos.failapi.enabled = false
simianarmy.chaos.faildns.enabled = false
simianarmy.chaos.faildynamodb.enabled = false
simianarmy.chaos.fails3.enabled = false
simianarmy.chaos.networkcorruption.enabled = false
simianarmy.chaos.networklatency.enabled = false
simianarmy.chaos.networkloss.enabled = false

# Force-detaching EBS volumes may cause data loss
simianarmy.chaos.detachvolumes.enabled = false

# FillDisk fills the root disk.
# NOTE: This may incur charges for an EBS root volume.  See burnmoney option.
simianarmy.chaos.burnio.enabled = false
# BurnIO causes disk activity on the root disk.
# NOTE: This may incur charges for an EBS root volume. See burnmoney option.
simianarmy.chaos.filldisk.enabled = false

# Where we know the chaos strategy will incur charges, we won't run it unless burnmoney is true.
simianarmy.chaos.burnmoney = false


# enable a specific ASG
# simianarmy.chaos.ASG.<asgName>.enabled = true
# simianarmy.chaos.ASG.<asgName>.probability = 1.0

# increase or decrease the termination limit for a specific ASG
# simianarmy.chaos.ASG.<asgName>.maxTerminationsPerDay = 1.0

# Enroll in mandatory terminations.  If a group has not had a
# termination within the windowInDays range then it will terminate
# one instance in the group with a 0.5 probability (at some point in
# the next 2 days an instance should be terminated), then
# do nothing again for windowInDays.  This forces "enabled" groups
# that have a probability of 0.0 to have terminations periodically.
simianarmy.chaos.mandatoryTermination.enabled = false
simianarmy.chaos.mandatoryTermination.windowInDays = 32
simianarmy.chaos.mandatoryTermination.defaultProbability = 0.5

# Enable notification for Chaos termination for a specific instance group
# simianarmy.chaos.<groupType>.<groupName>.notification.enabled = true

# Set the destination email the termination notification sent to for a specific instance group
# simianarmy.chaos.<groupType>.<groupName>.ownerEmail = foo@bar.com

# Set the source email that sends the termination notification
# simianarmy.chaos.notification.sourceEmail = foo@bar.com

# Enable notification for Chaos termination for all instance groups
#simianarmy.chaos.notification.global.enabled = true

# Set the destination email the termination notification is sent to for all instance groups
#simianarmy.chaos.notification.global.receiverEmail = foo@bar.com

# Set a prefix applied to the subject of all termination notifications
# Probably want to include a trailing space to separate from start of default text
#simianarmy.chaos.notification.subject.prefix = SubjectPrefix

# Set a suffix applied to the subject of all termination notifications
# Probably want to include an escaped space " \ " to separate from end of default text
#simianarmy.chaos.notification.subject.suffix =  \ SubjectSuffix

# Set a prefix applied to the body of all termination notifications
# Probably want to include a trailing space to separate from start of default text
#simianarmy.chaos.notification.body.prefix = BodyPrefix

# Set a suffix applied to the body of all termination notifications
# Probably want to include an escaped space " \ " to separate from end of default text
#simianarmy.chaos.notification.body.suffix =  \ BodySuffix

# Enable the email subject to be the same as the body, to include terminated instance and group information
#simianarmy.chaos.notification.subject.isBody = true
#set the tag filter on the ASGs to terminate only instances from the ASG with the this tag key and value
#simianarmy.chaos.ASGtag.key = chaos_monkey
#simianarmy.chaos.ASGtag.value = true

Actual Output

# The file contains the properties for Chaos Monkey.
# see documentation at:
# https://github.com/Netflix/SimianArmy/wiki/Configuration

# let chaos run
simianarmy.chaos.enabled = true

# don't allow chaos to kill (ie dryrun mode)
simianarmy.chaos.leashed = true

# set to "false" for Opt-In behavior, "true" for Opt-Out behavior
simianarmy.chaos.ASG.enabled = false

# uncomment this line to use tunable aggression
#simianarmy.client.chaos.class = com.netflix.simianarmy.tunable.TunablyAggressiveChaosMonkey

# default probability for all ASGs
simianarmy.chaos.ASG.probability = 1.0

# increase or decrease the termination limit
simianarmy.chaos.ASG.maxTerminationsPerDay = 1.0

# Strategies
simianarmy.chaos.shutdowninstance.enabled = true
simianarmy.chaos.blockallnetworktraffic.enabled = false
simianarmy.chaos.burncpu.enabled = false
simianarmy.chaos.killprocesses.enabled = false
simianarmy.chaos.nullroute.enabled = false
simianarmy.chaos.failapi.enabled = false
simianarmy.chaos.faildns.enabled = false
simianarmy.chaos.faildynamodb.enabled = false
simianarmy.chaos.fails3.enabled = false
simianarmy.chaos.networkcorruption.enabled = false
simianarmy.chaos.networklatency.enabled = false
simianarmy.chaos.networkloss.enabled = false

# Force-detaching EBS volumes may cause data loss
simianarmy.chaos.detachvolumes.enabled = false

# FillDisk fills the root disk.
# NOTE: This may incur charges for an EBS root volume.  See burnmoney option.
simianarmy.chaos.burnio.enabled = false
# BurnIO causes disk activity on the root disk.
# NOTE: This may incur charges for an EBS root volume. See burnmoney option.
simianarmy.chaos.filldisk.enabled = false

# Where we know the chaos strategy will incur charges, we won't run it unless burnmoney is true.
simianarmy.chaos.burnmoney = false


# enable a specific ASG
# simianarmy.chaos.ASG.<asgName>.enabled = true
# simianarmy.chaos.ASG.<asgName>.probability = 1.0

# increase or decrease the termination limit for a specific ASG
# simianarmy.chaos.ASG.<asgName>.maxTerminationsPerDay = 1.0

# Enroll in mandatory terminations.  If a group has not had a
# termination within the windowInDays range then it will terminate
# one instance in the group with a 0.5 probability (at some point in
# the next 2 days an instance should be terminated), then
# do nothing again for windowInDays.  This forces "enabled" groups
# that have a probability of 0.0 to have terminations periodically.
simianarmy.chaos.mandatoryTermination.enabled = false
simianarmy.chaos.mandatoryTermination.windowInDays = 32
simianarmy.chaos.mandatoryTermination.defaultProbability = 0.5

# Enable notification for Chaos termination for a specific instance group
# simianarmy.chaos.<groupType>.<groupName>.notification.enabled = true

# Set the destination email the termination notification sent to for a specific instance group
# simianarmy.chaos.<groupType>.<groupName>.ownerEmail = foo@bar.com

# Set the source email that sends the termination notification
# simianarmy.chaos.notification.sourceEmail = foo@bar.com

# Enable notification for Chaos termination for all instance groups
#simianarmy.chaos.notification.global.enabled = true

# Set the destination email the termination notification is sent to for all instance groups
#simianarmy.chaos.notification.global.receiverEmail = foo@bar.com

# Set a prefix applied to the subject of all termination notifications
# Probably want to include a trailing space to separate from start of default text
#simianarmy.chaos.notification.subject.prefix = SubjectPrefix

# Set a suffix applied to the subject of all termination notifications
# Probably want to include an escaped space " \ " to separate from end of default text
#simianarmy.chaos.notification.subject.suffix =  \ SubjectSuffix

# Set a prefix applied to the body of all termination notifications
# Probably want to include a trailing space to separate from start of default text
#simianarmy.chaos.notification.body.prefix = BodyPrefix

# Set a suffix applied to the body of all termination notifications
# Probably want to include an escaped space " \ " to separa# The file contains the properties for Chaos Monkey.
# see documentation at:
# https://github.com/Netflix/SimianArmy/wiki/Configuration

# let chaos run
simianarmy.chaos.enabled                                                        = {{getv "/simianarmy/chaos/enabled" "true"}}

# don't allow chaos to kill (ie dryrun mode)
simianarmy.chaos.leashed                                                        = {{getv "/simianarmy/chaos/leashed" "true"}}

# set to "false" for Opt-In behavior, "true" for Opt-Out behavior
simianarmy.chaos.ASG.enabled                                                    = {{getv "/simianarmy/chaos/asg/enabled" "false"}}

# uncomment this line to use tunable aggression
{{if exists "/simianarmy/client/chaos/class" -}}
simianarmy.client.chaos.class                                                   = {{getv "/simianarmy/client/chaos/class" "com.netflix.simianarmy.tunable.TunablyAggressiveChaosMonkey"}}
{{end -}}

# default probability for all ASGs
simianarmy.chaos.ASG.probability                                                = {{getv "/simianarmy/chaos/asg/probability" "1.0"}}

# increase or decrease the termination limit
simianarmy.chaos.ASG.maxTerminationsPerDay                                      = {{getv "/simianarmy/chaos/asg/maxterminationsperday" "1.0"}}

# Strategies
simianarmy.chaos.shutdowninstance.enabled                                       = {{getv "/simianarmy/chaos/shutdowninstance/enabled" "true"}}
simianarmy.chaos.blockallnetworktraffic.enabled                                 = {{getv "/simianarmy/chaos/blockallnetworktraffic/enabled" "false"}}
simianarmy.chaos.burncpu.enabled                                                = {{getv "/simianarmy/chaos/burncpu/enabled" "false"}}
simianarmy.chaos.killprocesses.enabled                                          = {{getv "/simianarmy/chaos/killprocesses/enabled" "false"}}
simianarmy.chaos.nullroute.enabled                                              = {{getv "/simianarmy/chaos/nullroute/enabled" "false"}}
simianarmy.chaos.failapi.enabled                                                = {{getv "/simianarmy/chaos/failapi/enabled" "false"}}
simianarmy.chaos.faildns.enabled                                                = {{getv "/simianarmy/chaos/faildns/enabled" "false"}}
simianarmy.chaos.faildynamodb.enabled                                           = {{getv "/simianarmy/chaos/faildynamodb/enabled" "false"}}
simianarmy.chaos.fails3.enabled                                                 = {{getv "/simianarmy/chaos/fails3/enabled" "false"}}
simianarmy.chaos.networkcorruption.enabled                                      = {{getv "/simianarmy/chaos/networkcorruption/enabled" "false"}}
simianarmy.chaos.networklatency.enabled                                         = {{getv "/simianarmy/chaos/networklatency/enabled" "false"}}
simianarmy.chaos.networkloss.enabled                                            = {{getv "/simianarmy/chaos/networkloss/enabled" "false"}}

# Force-detaching EBS volumes may cause data loss
simianarmy.chaos.detachvolumes.enabled                                          = {{getv "/simianarmy/chaos/detachvolumes/enabled" "false"}}

# FillDisk fills the root disk.
# NOTE: This may incur charges for an EBS root volume.  See burnmoney option.
simianarmy.chaos.burnio.enabled                                                 = {{getv "/simianarmy/chaos/burnio/enabled" "false"}}
# BurnIO causes disk activity on the root disk.
# NOTE: This may incur charges for an EBS root volume. See burnmoney option.
simianarmy.chaos.filldisk.enabled                                               = {{getv "/simianarmy/chaos/filldisk/enabled" "false"}}

# Where we know the chaos strategy will incur charges, we won't run it unless burnmoney is true.
simianarmy.chaos.burnmoney                                                      = {{getv "/simianarmy/chaos/burnmoney" "false"}}


# enable a specific ASG
{{if exists "/simianarmy/chaos/asg/<asgname>/enabled" -}}
simianarmy.chaos.ASG.<asgName>.enabled                                          = {{getv "/simianarmy/chaos/asg/<asgname>/enabled" "true"}}
{{end -}}
{{if exists "/simianarmy/chaos/asg/<asgname>/probability" -}}
simianarmy.chaos.ASG.<asgName>.probability                                      = {{getv "/simianarmy/chaos/asg/<asgname>/probability" "1.0"}}
{{end -}}

# increase or decrease the termination limit for a specific ASG
{{if exists "/simianarmy/chaos/asg/<asgname>/maxterminationsperday" -}}
simianarmy.chaos.ASG.<asgName>.maxTerminationsPerDay                            = {{getv "/simianarmy/chaos/asg/<asgname>/maxterminationsperday" "1.0"}}
{{end -}}

# Enroll in mandatory terminations.  If a group has not had a
# termination within the windowInDays range then it will terminate
# one instance in the group with a 0.5 probability (at some point in
# the next 2 days an instance should be terminated), then
# do nothing again for windowInDays.  This forces "enabled" groups
# that have a probability of 0.0 to have terminations periodically.
simianarmy.chaos.mandatoryTermination.enabled                                   = {{getv "/simianarmy/chaos/mandatorytermination/enabled" "false"}}
simianarmy.chaos.mandatoryTermination.windowInDays                              = {{getv "/simianarmy/chaos/mandatorytermination/windowindays" "32"}}
simianarmy.chaos.mandatoryTermination.defaultProbability                        = {{getv "/simianarmy/chaos/mandatorytermination/defaultprobability" "0.5"}}

# Enable notification for Chaos termination for a specific instance group
{{if exists "/simianarmy/chaos/<grouptype>/<groupname>/notification/enabled" -}}
simianarmy.chaos.<groupType>.<groupName>.notification.enabled                   = {{getv "/simianarmy/chaos/<grouptype>/<groupname>/notification/enabled" "true"}}
{{end -}}

# Set the destination email the termination notification sent to for a specific instance group
{{if exists "/simianarmy/chaos/<grouptype>/<groupname>/owneremail" -}}
simianarmy.chaos.<groupType>.<groupName>.ownerEmail                             = {{getv "/simianarmy/chaos/<grouptype>/<groupname>/owneremail" "foo@bar.com"}}
{{end -}}

# Set the source email that sends the termination notification
{{if exists "/simianarmy/chaos/notification/sourceemail" -}}
simianarmy.chaos.notification.sourceEmail                                       = {{getv "/simianarmy/chaos/notification/sourceemail" "foo@bar.com"}}
{{end -}}

# Enable notification for Chaos termination for all instance groups
{{if exists "/simianarmy/chaos/notification/global/enabled" -}}
simianarmy.chaos.notification.global.enabled                                    = {{getv "/simianarmy/chaos/notification/global/enabled" "true"}}
{{end -}}

# Set the destination email the termination notification is sent to for all instance groups
{{if exists "/simianarmy/chaos/notification/global/receiveremail" -}}
simianarmy.chaos.notification.global.receiverEmail                              = {{getv "/simianarmy/chaos/notification/global/receiveremail" "foo@bar.com"}}
{{end -}}

# Set a prefix applied to the subject of all termination notifications
# Probably want to include a trailing space to separate from start of default text
{{if exists "/simianarmy/chaos/notification/subject/prefix" -}}
simianarmy.chaos.notification.subject.prefix                                    = {{getv "/simianarmy/chaos/notification/subject/prefix" "SubjectPrefix"}}
{{end -}}

# Set a suffix applied to the subject of all termination notifications
# Probably want to include an escaped space " \ " to separate from end of default text
{{if exists "/simianarmy/chaos/notification/subject/suffix" -}}
simianarmy.chaos.notification.subject.suffix                                    = {{getv "/simianarmy/chaos/notification/subject/suffix" "\ SubjectSuffix"}}
{{end -}}

# Set a prefix applied to the body of all termination notifications
# Probably want to include a trailing space to separate from start of default text
{{if exists "/simianarmy/chaos/notification/body/prefix" -}}
simianarmy.chaos.notification.body.prefix                                       = {{getv "/simianarmy/chaos/notification/body/prefix" "BodyPrefix"}}
{{end -}}

# Set a suffix applied to the body of all termination notifications
# Probably want to include an escaped space " \ " to separa
  • 写回答

1条回答 默认 最新

  • doumaikuang4202 2018-02-15 00:29
    关注

    It appends data because the cursor is at the end of the file when you finish reading. You can use Seek() to move the cursor, or just open it in reading more (os.Open()) and then overwrite (os.Create()) when you are done with reading.

    评论

报告相同问题?

悬赏问题

  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 关于大棚监测的pcb板设计
  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入