web-dev-qa-db-ja.com

Goを使ってファイルを読み書きするにはどうすればいいですか?

私は自分でGoを勉強しようとしていましたが、普通のファイルから読み書きしようとするのに困惑しました。

inFile, _ := os.Open(INFILE, 0, 0)まで取得できますが、実際にはファイルの内容を取得するのは意味がありません。なぜならread関数は[]byteをパラメータとして受け取るからです。

func (file *File) Read(b []byte) (n int, err Error)
266
Seth Hoenig

Goでファイルを読み書きするためのすべての方法のGo 1互換リストを作りましょう。

ファイル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.Openos.Createを使いました。これらはos.OpenFileの便利なラッパーです。通常OpenFileを直接呼び出す必要はありません。

EOFの扱いに注意してください。 Readは、呼び出しのたびにbufを埋めようとし、ファイルの終わりに達するとエラーとしてio.EOFを返します。この場合bufはまだデータを保持しています。後続のReadへの呼び出しは、読み取られたバイト数としてゼロを返し、errorと同じ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はバックグラウンドでのバッファリングを処理しながら、簡単かつ柔軟に読み書きするために Nice 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)
    }
}

やさしい!ただし、大きなファイルを扱っていないことが確実な場合にのみ使用してください。

447
Mostafa

これは良いバージョンです。

package main

import (
  "io/ioutil"; 
  )


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

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.Copyio.CopyNが役に立ちます。 io.Copy関数の ソースをチェックする ならば、それはGoライブラリにパッケージされているMostafaのソリューションの1つ(実際には '基本'のソリューション)に他なりません。しかし、彼らは彼よりもかなり大きいバッファを使用しています。

26
user7610

[]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();
}
10
peterSO

新しいバージョンの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")
}

これにより、ファイルの内容が上書きされます(存在しない場合は新しいファイルを作成します)。

8
Salvador Dali

これを試して:

package main

import (
  "io"; 
  )


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

Readメソッドはbyteパラメータを受け取ります。これが、読み込み先のバッファだからです。それはいくつかの分野で共通の慣用句であり、あなたがそれについて考えるときいくつかの理にかなっています。

このようにして、読者によって何バイト読まれるかを決定し、リターンを調べて実際に何バイト読まれたかを確認し、適切にエラーを処理することができます。

他の人が彼らの答えで指摘したように、bufioはおそらくあなたがたいていのファイルから読むために欲しいものです。

ヒントがもう1つ追加されます。本当に便利なので。ファイルからの行の読み取りは、ReadLineメソッドではなくReadBytesメソッドまたはReadStringメソッドを使用するのが最も効果的です。

1
Jeremy Wall

ドキュメンテーションを見るだけで、あなたはただタイプ[] byteのバッファを宣言し、それをreadに渡すべきであると思われます、そしてそれはそれからその多くの文字まで読んで、そして実際に読んだ文字数を返します(そしてエラー)。

The docs say

ReadはFileからlen(b)バイトまで読み込みます。読み込んだバイト数と、もしあればErrorを返します。 EOFは、errがEOFに設定されたゼロカウントによって通知されます。

それはうまくいきませんか?

編集:また、私はあなたがosパッケージを使用する代わりにbufioパッケージで宣言されたReader/Writerインターフェースを使用するべきであると私は思う。

1
Hannes Ovrén