Jak mogę wczytać cały plik do zmiennej łańcuchowej

161

Mam dużo małych plików, nie chcę ich czytać linijka po linijce.

Czy w Go jest funkcja, która wczyta cały plik do zmiennej łańcuchowej?

WoooHaaaa
źródło

Odpowiedzi:

253

Zastosowanie ioutil.ReadFile:

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

ReadFile czyta plik o nazwie nazwa_pliku i zwraca zawartość. Pomyślne wywołanie zwraca err == nil, a nie err == EOF. Ponieważ ReadFile odczytuje cały plik, nie traktuje EOF z Read jako błędu do zgłoszenia.

Otrzymasz []bytezamiast string. To może być przekształcony czy naprawdę konieczne:

s := string(buf)
zzzz
źródło
5
Następnie, aby skonstruować końcowy wynik w postaci ciągu, możesz użyć metody append (), aby zgromadzić dane w pojedynczym wycinku bajtowym podczas odczytu każdego pliku, a następnie przekonwertować skumulowany segment bajtów na końcowy wynik w postaci ciągu. Alternatywnie możesz polubić bytes.Join.
Sonia
1
Pokaż nam, jak to przekonwertować ... Pytanie nie dotyczy tablicy bajtów.
Kyle Bridenstine,
Używając tego do otwarcia pliku html i stwierdzam, że po każdym wierszu jest dodawany nowy wiersz, który psuje nam część mojego formatowania. Czy jest sposób, aby tego uniknąć?
Jonathan
55

Jeśli chcesz, aby zawartość była po prostu jako string, prostym rozwiązaniem jest użycie ReadFilefunkcji z io/ioutilpakietu. Ta funkcja zwraca wycinek, bytesktóry można łatwo przekonwertować na plik 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
źródło
22

Myślę, że najlepszą rzeczą do zrobienia, jeśli naprawdę martwisz się o skuteczność łączenia wszystkich tych plików, jest skopiowanie ich wszystkich do tego samego bufora bajtów.

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

To otwiera każdy plik, kopiuje jego zawartość do bufora, a następnie zamyka plik. W zależności od sytuacji, w rzeczywistości konwersja może nie być konieczna, ostatnia linia służy po prostu do pokazania, że ​​buf.Bytes () zawiera dane, których szukasz.

Running Wild
źródło
Cześć, czy io.Copy nadpisze zawartość bufora? A jaka jest pojemność buforu? Dzięki.
WoooHaaaa
Kopiowanie nie nadpisze, będzie po prostu dodawać do bufora, a wartość buf będzie rosła tak bardzo, jak potrzeba, aby pomieścić nowe dane.
Running Wild
1
Bufor ma „nieskończoną” pojemność. Będzie się nadal rozwijać w miarę dodawania kolejnych danych. ioutil.Readfile przydzieli bufor, który jest wystarczająco duży, aby zmieścić cały plik i nie trzeba go ponownie przydzielać.
Stephen Weinberg
1
Czy użycie bufora bajtów naprawdę poprawia wydajność w porównaniu do prostego dodawania go do plasterka (/ tablicy)? A co z pamięcią? Jak duża jest różnica?
Kissaki
8

Oto jak to zrobiłem:

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
źródło
-2

Nie mam komputera, więc piszę szkic. Możesz być pewien, co mówię.

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
źródło