回答:
Goでファイルを読み書きするすべての方法のGo 1互換リストを作成しましょう。
ファイル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
データとは関係がないため、ここではバッファとして機能しています。他のほとんどの状況(特にテキストファイルの場合)では、バックグラウンドでバッファリングを処理しながら、簡単かつ柔軟に読み書きするための優れたAPIをbufio
提供することが非常に便利です。
使用する 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)
}
}
やさしい!ただし、大きなファイルを処理していないことが確実な場合にのみ使用してください。
panic("error in writing")
)の追加のチェックは必要ありません。
これは良いバージョンです:
package main
import (
"io/ioutil";
)
func main() {
contents,_ := ioutil.ReadFile("plikTekstowy.txt")
println(string(contents))
ioutil.WriteFile("filename", contents, 0644)
}
0x777
偽物です。いずれにせよ、それは0644
or 0755
(16進数ではなく8進数)に近いはずです。
使用する 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つにすぎません。しかし、彼らは彼よりもかなり大きなバッファを使用しています。
w.Sync()
後に使用する必要がありますio.Copy(w, r)
io.Copy()
書き込む場合は、フィードしたデータのみが書き込まれるため、既存のファイルにさらにコンテンツが含まれている場合は削除されず、ファイルが破損する可能性があります。
w, err := os.Create("output.txt")
、何を説明することは発生しませんので、「作成という名前のファイルを作成するか、切り捨てる。ファイルが既に存在する場合、それが切り捨てられます。」golang.org/pkg/os/#Create。
新しい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")
}
これにより、ファイルの内容が上書きされます(ファイルがなかった場合は、新しいファイルを作成します)。
[]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();
}
if
ブロックの外側に
これを試して:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
ドキュメントを見るだけで、[] byteタイプのバッファを宣言し、それをreadに渡して、それまでに多くの文字を読み取り、実際に読み取った文字数(およびエラー)を返す必要があるようです。
ドキュメントは言う
読み取りは、ファイルから最大len(b)バイトを読み取ります。読み込まれたバイト数と、もしあればエラーを返します。EOFは、errがEOFに設定されたゼロカウントによって通知されます。
それはうまくいきませんか?
編集:また、おそらく、osパッケージを使用する代わりに、bufioパッケージで宣言されたリーダー/ライターインターフェイスを使用する必要があると思います。
Readメソッドは、それが読み込むバッファーであるため、byteパラメーターを取ります。これは一部のサークルでは一般的なイディオムであり、考えてみるとある程度の意味があります。
このようにして、リーダーによって読み取られるバイト数を決定し、戻りを検査して実際に読み取られたバイト数を確認し、エラーを適切に処理できます。
他の人が回答で指摘しているように、bufioはおそらくほとんどのファイルから読み取るためのものです。
本当に便利なので、もう1つヒントを追加します。ファイルから行を読み取るには、ReadLineメソッドではなく、ReadBytesまたはReadStringメソッドを使用するのが最適です。