【问题标题】:How can I read a whole file into a string variable如何将整个文件读入字符串变量
【发布时间】:2012-11-10 22:32:26
【问题描述】:

我有很多小文件,我不想逐行阅读。

Go 中是否有将整个文件读入字符串变量的函数?

【问题讨论】:

    标签: string file go


    【解决方案1】:

    你可以使用strings.Builder:

    package main
    
    import (
       "io"
       "os"
       "strings"
    )
    
    func main() {
       f, err := os.Open("file.txt")
       if err != nil {
          panic(err)
       }
       defer f.Close()
       b := new(strings.Builder)
       io.Copy(b, f)
       print(b.String())
    }
    

    或者如果你不介意[]byte,你可以使用 os.ReadFile:

    package main
    import "os"
    
    func main() {
       b, err := os.ReadFile("file.txt")
       if err != nil {
          panic(err)
       }
       os.Stdout.Write(b)
    }
    

    【讨论】:

    • 正如@Cerise Limón 的回答suggests“您可以通过在读取之前将构建器增大到文件大小来改进strings.Builder 示例”;我们可以先fi, _ := f.Stat()b.Grow(int(fi.Size()))io.Copy(b, f)
    【解决方案2】:

    我不会用电脑,所以我写了一个草稿。你可能对我说的很清楚。

    func main(){
        const dir = "/etc/"
        filesInfo, e := ioutil.ReadDir(dir)
        var fileNames = make([]string, 0, 10)
        for i,v:=range filesInfo{
            if !v.IsDir() {
                fileNames = append(fileNames, v.Name())
            }
        }
    
        var fileNumber = len(fileNames)
        var contents = make([]string, fileNumber, 10)
        wg := sync.WaitGroup{}
        wg.Add(fileNumber)
    
        for i,_:=range content {
            go func(i int){
                defer wg.Done()
                buf,e := ioutil.Readfile(fmt.Printf("%s/%s", dir, fileName[i]))
                defer file.Close()  
                content[i] = string(buf)
            }(i)   
        }
        wg.Wait()
    }
    

    【讨论】:

      【解决方案3】:

      我就是这样做的:

      package main
      
      import (
        "fmt"
        "os"
        "bytes"
        "log"
      )
      
      func main() {
         filerc, err := os.Open("filename")
         if err != nil{
           log.Fatal(err)
         }
         defer filerc.Close()
      
         buf := new(bytes.Buffer)
         buf.ReadFrom(filerc)
         contents := buf.String()
      
         fmt.Print(contents) 
      
      }    
      

      【讨论】:

      • 虽然 ioutil.ReadFile 更简洁,因此在文件尚未打开时更可取,但 buf.ReadFrom() 在您已经获得打开文件的情况下有效,因此它是一个很好的选择第二个答案。
      【解决方案4】:

      使用ioutil.ReadFile:

      func ReadFile(filename string) ([]byte, error)
      

      ReadFile 读取以 filename 命名的文件并返回内容。一次成功的通话 返回 err == nil,而不是 err == EOF。因为 ReadFile 读取整个文件,所以它不处理 来自 Read 的 EOF 作为要报告的错误。

      您将获得[]byte 而不是string。如果真的需要,可以转换:

      s := string(buf)
      

      【讨论】:

      • 那么为了构造最终的字符串结果,您可以在读取每个文件时使用 append() 将数据累积在单个字节切片中,然后将累积的字节切片转换为最终的字符串结果。或者,您可能喜欢 bytes.Join。
      • 然后向我们展示如何转换它...问题不要求字节数组。
      • 使用它打开一个 html 文件,我发现在每一行之后都附加了一个新行,这让我们的一些格式变得混乱。有什么办法可以避免吗?
      • golang 是强类型的。如果您需要类型字符串而不是 []byte,则转换是真的 必要的。很高兴 string(bytes) 完成了工作。
      【解决方案5】:

      如果您只希望内容为string,那么简单的解决方案是使用io/ioutil 包中的ReadFile 函数。此函数返回bytes 的切片,您可以轻松地将其转换为string

      package main
      
      import (
          "fmt"
          "io/ioutil"
      )
      
      func main() {
          b, err := ioutil.ReadFile("file.txt") // just pass the file name
          if err != nil {
              fmt.Print(err)
          }
      
          fmt.Println(b) // print the content as 'bytes'
      
          str := string(b) // convert content to a 'string'
      
          fmt.Println(str) // print the content as a 'string'
      }
      

      【讨论】:

        【解决方案6】:

        如果您真的关心连接所有这些文件的效率,我认为最好的办法是将它们全部复制到相同的字节缓冲区中。

        buf := bytes.NewBuffer(nil)
        for _, filename := range filenames {
          f, _ := os.Open(filename) // Error handling elided for brevity.
          io.Copy(buf, f)           // Error handling elided for brevity.
          f.Close()
        }
        s := string(buf.Bytes())
        

        这会打开每个文件,将其内容复制到 buf,然后关闭文件。根据您的情况,您可能实际上不需要转换它,最后一行只是显示 buf.Bytes() 具有您要查找的数据。

        【讨论】:

        • 嗨,io.Copy 会覆盖 buf 的内容吗? buf 的容量是多少?谢谢。
        • 复制不会覆盖,它只会不断添加到 buf,并且 buf 会根据需要增长以容纳新数据。
        • buf 具有“无限”容量。随着更多数据的添加,它将继续扩展。 ioutil.Readfile 将分配一个足够大的缓冲区以容纳整个文件,而无需重新分配。
        • 与简单地将字节缓冲区附加到切片(/数组)相比,使用字节缓冲区真的能提高性能吗?内存呢?差别有多大?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-12
        • 1970-01-01
        • 1970-01-01
        • 2021-06-04
        相关资源
        最近更新 更多