私は自分でGoを学ぼうとしていましたが、通常のファイルからの読み取りと書き込みを試みることに困惑していました。
まで取得できますが、読み取り関数がパラメーターとしてを取得するためinFile, _ := os.Open(INFILE, 0, 0)
、実際にファイルのコンテンツを取得することは意味がありません。[]byte
func (file *File) Read(b []byte) (n int, err Error)
Goでファイルを読み書きするすべての方法のGo1互換リストを作成しましょう。
ファイルAPIが最近変更され、他のほとんどの回答がGo 1で機能しないためです。また、bufio
重要なIMHOを見逃しています。
次の例では、ファイルから読み取り、宛先ファイルに書き込むことによってファイルをコピーします。
基本から始める
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
データとはあまり関係がないため、ここではバッファとして機能しているだけです。他のほとんどの状況(特にテキストファイルの場合)では、バックグラウンドでのバッファリングを処理しながら、簡単かつ柔軟に読み取りと書き込みを行うための優れたAPIbufio
を提供することで非常に便利です。
注:次のコードは、古いバージョンのGo(Go 1.15以前)用です。世の中変わったんだよ。新しい方法については、この回答をご覧ください。
使用する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つ(実際には「基本的な」ソリューション)にすぎません。しかし、彼らは彼よりもかなり大きなバッファーを使用しています。
新しいバージョンの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")
}
これにより、ファイルの内容が上書きされます(ファイルがない場合は新しいファイルを作成します)。
Go 1.16以降では、os.ReadFileを使用してファイルをメモリにロードし、を使用os.WriteFile
してメモリからファイルに書き込みます(ioutil.ReadFileは現在を呼び出しますos.ReadFile
)。
os.ReadFile
ファイル全体がメモリに読み込まれるため、注意してください。
package main
import "os"
func main() {
b, err := os.ReadFile("input.txt")
if err != nil {
log.Fatal(err)
}
// `b` contains everything your file does
// This writes it to the Standard Out
os.Stdout.Write(b)
// You can also write it to a file as a whole
err = os.WriteFile("destination.txt", b, 0644)
if err != nil {
log.Fatal(err)
}
}
[]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);
}
fmt
パッケージも使用できます。
package main
import "fmt"
func main(){
file, err := os.Create("demo.txt")
if err != nil {
panic(err)
}
defer file.Close()
fmt.Fprint(file, name)
}
ドキュメントを見るだけで、[] byte型のバッファを宣言し、それを読み取りに渡す必要があるようです。これにより、その数まで読み取り、実際に読み取られた文字数(およびエラー)が返されます。
ドキュメントは言う
読み取りは、ファイルから最大len(b)バイトを読み取ります。読み取られたバイト数と、存在する場合はエラーを返します。EOFは、errがEOFに設定されたゼロカウントによって通知されます。
それはうまくいきませんか?
編集:また、 osパッケージを使用する代わりに、 bufioパッケージで宣言されたリーダー/ライターインターフェイスを使用する必要があると思います。
Readメソッドは、バイトパラメーターを受け取ります。これは、バイトパラメーターが読み込まれるバッファーであるためです。これは一部のサークルでは一般的なイディオムであり、考えてみると理にかなっています。
このようにして、リーダーによって読み取られるバイト数を決定し、戻り値を調べて実際に読み取られたバイト数を確認し、エラーを適切に処理できます。
他の人が彼らの答えで指摘しているように、bufioはおそらくあなたがほとんどのファイルから読みたいものです。
本当に便利なので、もう1つヒントを追加します。ファイルから行を読み取るには、ReadLineメソッドではなく、ReadBytesまたはReadStringメソッドを使用するのが最適です。