¿Cómo puedo leer un archivo completo en una variable de cadena?

161

Tengo muchos archivos pequeños, no quiero leerlos línea por línea.

¿Hay una función en Go que lea un archivo completo en una variable de cadena?

WoooHaaaa
fuente

Respuestas:

253

Uso ioutil.ReadFile:

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

ReadFile lee el archivo nombrado por nombre de archivo y devuelve el contenido. Una llamada exitosa devuelve err == nil, no err == EOF. Debido a que ReadFile lee todo el archivo, no trata un EOF de Read como un error que se debe informar.

Obtendrá un en []bytelugar de un string. Se puede convertir si es realmente necesario:

s := string(buf)
zzzz
fuente
55
Luego, para construir el resultado final de la cadena, puede usar append () para acumular los datos en un segmento de un solo byte a medida que lee cada archivo, y luego convertir el segmento de byte acumulado en el resultado final de la cadena. Alternativamente, te pueden gustar bytes.Join.
Sonia
1
Muéstrenos cómo convertirlo entonces ... La pregunta no pide una matriz de bytes.
Kyle Bridenstine
Usando esto para abrir un archivo html y encuentro que se agrega una nueva línea después de cada línea, lo que nos está alterando un poco mi formato. ¿Hay alguna manera de evitar eso?
Jonathan
55

Si solo desea el contenido como string, entonces la solución simple es usar la ReadFilefunción del io/ioutilpaquete. Esta función devuelve una porción de la bytescual puede convertir fácilmente a 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'
}
openwonk
fuente
22

Creo que lo mejor que puedes hacer, si realmente te preocupa la eficacia de concatenar todos estos archivos, es copiarlos en el mismo búfer de bytes.

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())

Esto abre cada archivo, copia su contenido en buf, luego cierra el archivo. Dependiendo de su situación, es posible que no necesite convertirlo, la última línea es solo para mostrar que buf.Bytes () tiene los datos que está buscando.

Corriendo salvajemente
fuente
Hola, ¿io.Copy sobrescribirá el contenido de buf? ¿Y cuál es la capacidad de buf? Gracias.
WoooHaaaa
La copia no se sobrescribirá, solo se seguirá agregando a buf, y buf crecerá tanto como sea necesario para acomodar los nuevos datos.
Running Wild
1
El buf tiene una capacidad "infinita". Continuará expandiéndose a medida que se agreguen más datos. ioutil.Readfile asignará un búfer lo suficientemente grande como para caber en el archivo completo y no necesitará reasignarlo.
Stephen Weinberg el
1
¿Usar un bytebuffer realmente mejora el rendimiento en comparación con simplemente agregarlo al segmento (/ array)? ¿Qué hay de la memoria? ¿Qué tan grande es la diferencia?
Kissaki
8

Así es como lo hice:

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) 

}    
Mo-Gang
fuente
-2

No estoy con la computadora, así que escribo un borrador. Podrías estar claro de lo que digo.

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()
}
fwhez
fuente