Как читать / записывать из / в файл с помощью Go?



Я пытался научиться идти самостоятельно, но я был в тупике, пытаясь читать и писать в обычные файлы.



Я могу добраться до inFile, _ := os.Open(INFILE, 0, 0), но на самом деле получить содержание файла не имеет смысла, потому что функция read принимает []byte в качестве параметра.



func (file *File) Read(b []byte) (n int, err Error)
578   8  

8 ответов:

давайте сделаем Go 1-совместимый список всех способов чтения и записи файлов в Go.

потому что API файлов недавно изменился, и большинство других ответов не работают с Go 1. Они тоже скучают bufio что важно ИМХО.

в следующих примерах я копирую файл, читать из него и писать в файл назначения.

начните с основ

package main

import (
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

здесь я использовал os.Open и os.Create, которые удобные обертки вокруг os.OpenFile. Обычно нам не нужно звонить OpenFile напрямую.

обратите внимание на лечение EOF. Read пытается заполнить buf при каждом вызове, и возвращает io.EOF как ошибка, если она достигает конца файла при этом. В данном случае buf сохраняет данные. Последовательные звонки в Read возвращает ноль как количество прочитанных байтов и то же самое io.EOF ошибка. Любая другая ошибка приведет к панике.

используя bufio

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()
    // make a read buffer
    r := bufio.NewReader(fi)

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()
    // make a write buffer
    w := bufio.NewWriter(fo)

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

bufio здесь просто действует как буфер, потому что мы не имеем большого отношения к данным. В большинстве других ситуаций (особенно с текстовыми файлами) bufio - Это очень полезно, давая нам хороший API для чтения и записи легко и гибко, в то время как он обрабатывает буферизации за кулисами.

используя ioutil

package main

import (
    "io/ioutil"
)

func main() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

легко, как пирог! Но используйте его только если вы уверены, что не имеете дело с большими файлы.

Это хороший вариант:

package main

import (
  "io/ioutil"; 
  )


func main() {
  contents,_ := ioutil.ReadFile("plikTekstowy.txt")
  println(string(contents))
  ioutil.WriteFile("filename", contents, 0644)
}

используя io.Copy

package main

import (
    "io"
    "log"
    "os"
)

func main () {
    // open files r and w
    r, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer r.Close()

    w, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer w.Close()

    // do the actual work
    n, err := io.Copy(w, r)
    if err != nil {
        panic(err)
    }
    log.Printf("Copied %v bytes\n", n)
}

если вы не хотите изобретать велосипед, то io.Copy и io.CopyN может служить вам хорошо. Если вы проверьте источник из io.Функция копирования, это не что иное, как одно из решений Mostafa (на самом деле "основное"), упакованное в библиотеку Go. Однако они используют значительно больший буфер, чем он.

[]byte - Это фрагмент (похожий на подстроку) всего или части массива байтов. Подумайте о срезе как о структуре значений со скрытым полем указателя для системы, чтобы найти и получить доступ ко всему или части массива (срез), а также поля для длины и емкости среза, к которым вы можете получить доступ с помощью len() и cap() функции.

вот рабочий стартовый комплект для вас, который читает и печатает двоичный файл; вам нужно будет изменить inName буквальное значение, указывающее к небольшому файлу в вашей системе.

package main
import (
    "fmt";
    "os";
)
func main()
{
    inName := "file-rw.bin";
    inPerm :=  0666;
    inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
    if inErr == nil {
        inBufLen := 16;
        inBuf := make([]byte, inBufLen);
        n, inErr := inFile.Read(inBuf);
        for inErr == nil {
            fmt.Println(n, inBuf[0:n]);
            n, inErr = inFile.Read(inBuf);
        }
    }
    inErr = inFile.Close();
}

попробуйте это:

package main

import (
  "io"; 
  )


func main() {
  contents,_ := io.ReadFile("filename");
  println(string(contents));
  io.WriteFile("filename", contents, 0644);
}

какие новые версии Go, чтение / запись в / из файла легко. Читать из файла:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("text.txt")
    if err != nil {
        return
    }
    fmt.Println(string(data))
}

для записи в файл:

package main

import "os"

func main() {
    file, err := os.Create("text.txt")
    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("test\nhello")
}

это перезапишет содержимое файла (создайте новый файл, если его там не было).

просто глядя на документацию, кажется, что вы должны просто объявить буфер типа []байт и передать его для чтения, который затем прочитает до этого количества символов и вернет количество фактически прочитанных символов (и ошибку).

документы сказать

Read считывает до LEN (b) байт из файла. Он возвращает количество прочитанных байтов и ошибку, если таковые имеются. EOF сигнализируется нулевым количеством с err, установленным в EOF.

тут что не работает?

EDIT: кроме того, я думаю, что вы, возможно, должны использовать интерфейсы чтения/записи, объявленные в bufio пакет вместо использования os пакета.

метод Read принимает параметр byte, потому что это буфер, в который он будет считываться. Это распространенная идиома в некоторых кругах и имеет некоторый смысл, когда вы думаете об этом.

таким образом, вы можете определить, сколько байтов будет прочитано читателем и проверить возврат, чтобы увидеть, сколько байтов на самом деле были прочитаны и обрабатывать любые ошибки соответствующим образом.

как другие указали в своих ответах bufio, вероятно, то, что вы хотите для чтения из большинства файлов.

Я добавлю еще один намек, так как это действительно полезно. Чтение строки из файла лучше всего выполнять не методом ReadLine,а методом ReadBytes или ReadString.

Comments

    Ничего не найдено.