dounai6613 2018-10-10 14:43
浏览 432
已采纳

使用golang写入文件字节进行优化

I have the following program that prints out information about each certificate in a .pem file:

package main

import (
    "crypto/x509"
    "encoding/pem"
    "io/ioutil"
    "log"
    "os"
    "strconv"
)

func main() {
    //for dev purposes set to 256
    const SignatureLength int = 256

    certPEMBlock, err := ioutil.ReadFile("testsign.crt")
    if err != nil {
        log.Fatal(err)
    }

    var blocks [][]byte
    for {
        var certDERBlock *pem.Block
        certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
        if certDERBlock == nil {
            break
        }

        if certDERBlock.Type == "CERTIFICATE" {
            blocks = append(blocks, certDERBlock.Bytes)
        }
    } //end for

    //OPEN FILE TO APPEND CERT INFORMATION INTO
    f, err := os.OpenFile("appendMe.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }

    for _, block := range blocks {
        cert, err := x509.ParseCertificate(block)
        if err != nil {
            log.Println(err)
            continue
        }

        //APPEND CERT INFO TO FILE
        //VERSION
        if _, err := f.Write([]byte(strconv.Itoa(cert.Version))); err != nil {
            log.Fatal(err)
        }
        //KEY ID
        if _, err := f.Write(cert.SubjectKeyId); err != nil {
            log.Fatal(err)
        }
        //SIGNATURE LENGTH
        if _, err := f.Write([]byte(strconv.Itoa(SignatureLength))); err != nil {
            log.Fatal(err)
        }
        //COMMON NAME
        if _, err := f.Write([]byte(cert.Subject.CommonName)); err != nil {
            log.Fatal(err)
        }

    } //end for

    //CLOSE THE FILE
    if err := f.Close(); err != nil {
        log.Fatal(err)
    }
}

it works, but notice that each line separately writes to the file. That seems a bit wasteful, but I am not clear about options in Go...do I create an array...do I slice it from the cert...another for loop...

QUESTION

Instead of f.Write() on each line, what is the proper or alternative approach in Go?

Instead of using the cert.*, should I be capturing that data into a struct or array?

Follow up

let's say the last write or any write fails, does Go roll back changes or does last write not get written to the file? This needs to be an all or nothing write.

(this is me learning as I do, thanks for your help)

  • 写回答

1条回答 默认 最新

  • doris20141022 2018-10-10 20:58
    关注

    The easiest way to write to a buffer in memory is using the bytes package, which provides a Buffer type. Since Buffer implements the Writer interface, you can update your Write calls to use the Buffer instead, and then use the Buffer.WriteTo method to write the accumulated data out to the file. Here's what that looks like, with the loops combined also:

    package main
    
    import (
        "bytes"
        "crypto/x509"
        "encoding/pem"
        "io/ioutil"
        "log"
        "os"
        "strconv"
    )
    
    func main() {
        //for dev purposes set to 256
        const SignatureLength int = 256
    
        certPEMBlock, err := ioutil.ReadFile("testsign.crt")
        if err != nil {
            log.Fatal(err)
        }
    
        //OPEN FILE TO APPEND CERT INFORMATION INTO
        f, err := os.OpenFile("appendMe.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
        if err != nil {
            log.Fatal(err)
        }
    
        var buf bytes.Buffer
        for {
            var certDERBlock *pem.Block
            certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
            if certDERBlock == nil {
                break
            }
    
            if certDERBlock.Type == "CERTIFICATE" {
                cert, err := x509.ParseCertificate(certDERBlock.Bytes)
                if err != nil {
                    log.Println(err)
                    continue
                }
    
                //APPEND CERT INFO TO FILE
                //VERSION
                if _, err := buf.Write([]byte(strconv.Itoa(cert.Version))); err != nil {
                    log.Fatal(err)
                }
                //KEY ID
                if _, err := buf.Write(cert.SubjectKeyId); err != nil {
                    log.Fatal(err)
                }
                //SIGNATURE LENGTH
                if _, err := buf.Write([]byte(strconv.Itoa(SignatureLength))); err != nil {
                    log.Fatal(err)
                }
                //COMMON NAME
                if _, err := buf.Write([]byte(cert.Subject.CommonName)); err != nil {
                    log.Fatal(err)
                }
            }
        } //end for
    
        // write data accumulated in buf out to f
        buf.WriteTo(f)
    
        //CLOSE THE FILE
        if err := f.Close(); err != nil {
            log.Fatal(err)
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 sub地址DHCP问题
  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大