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

使用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)
        }
    }
    
    已采纳该答案
    打赏 评论

相关推荐 更多相似问题