私は自分でGoを勉強しようとしていましたが、普通のファイルから読み書きしようとするのに困惑しました。
inFile, _ := os.Open(INFILE, 0, 0)
まで取得できますが、実際にはファイルの内容を取得するのは意味がありません。なぜならread関数は[]byte
をパラメータとして受け取るからです。
func (file *File) Read(b []byte) (n int, err Error)
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.Open
とos.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)
}
}
やさしい!ただし、大きなファイルを扱っていないことが確実な場合にのみ使用してください。
これは良いバージョンです。
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.Copy関数の ソースをチェックする ならば、それはGoライブラリにパッケージされているMostafaのソリューションの1つ(実際には '基本'のソリューション)に他なりません。しかし、彼らは彼よりもかなり大きいバッファを使用しています。
[]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();
}
新しいバージョンの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")
}
これにより、ファイルの内容が上書きされます(存在しない場合は新しいファイルを作成します)。
これを試して:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
Readメソッドはbyteパラメータを受け取ります。これが、読み込み先のバッファだからです。それはいくつかの分野で共通の慣用句であり、あなたがそれについて考えるときいくつかの理にかなっています。
このようにして、読者によって何バイト読まれるかを決定し、リターンを調べて実際に何バイト読まれたかを確認し、適切にエラーを処理することができます。
他の人が彼らの答えで指摘したように、bufioはおそらくあなたがたいていのファイルから読むために欲しいものです。
ヒントがもう1つ追加されます。本当に便利なので。ファイルからの行の読み取りは、ReadLineメソッドではなくReadBytesメソッドまたはReadStringメソッドを使用するのが最も効果的です。
ドキュメンテーションを見るだけで、あなたはただタイプ[] byteのバッファを宣言し、それをreadに渡すべきであると思われます、そしてそれはそれからその多くの文字まで読んで、そして実際に読んだ文字数を返します(そしてエラー)。
The docs say
ReadはFileからlen(b)バイトまで読み込みます。読み込んだバイト数と、もしあればErrorを返します。 EOFは、errがEOFに設定されたゼロカウントによって通知されます。
それはうまくいきませんか?
編集:また、私はあなたがosパッケージを使用する代わりにbufioパッケージで宣言されたReader/Writerインターフェースを使用するべきであると私は思う。