Reader/Writer, bufio, embed, path ปลอดภัย
f, err := os.Open("a.txt")
if err != nil {
if errors.Is(err, os.ErrNotExist) { fmt.Println("ไม่มีไฟล์") }
return err
}
defer f.Close() // สัญญาว่าปิดแน่ ไม่ว่าจะ return ทางไหน
b, err := io.ReadAll(f) // ไฟล์เล็กอ่านรวดเดียวได้
// ไฟล์เล็กมากๆ ใช้ os.ReadFile / os.WriteFile สั้นกว่า
data, _ := os.ReadFile("config.json")
_ = os.WriteFile("out.txt", data, 0644)กฎ: เปิดแล้ว defer Close() ทันทีบรรทัดถัดไป อย่าเว้น
// Reader = ที่ดูดออก, Writer = ที่เทเข้า, ReadWriter = ทั้งคู่
func (f *File) Read(buf []byte) (n int, err error)
n, err := f.Read(buf[0:32]) // อ่าน 32 byte แรกต่อท่อด้วย io.Copy (ก็อปไฟล์/โหลด/อัพโหลด):
src, _ := os.Open("in.zip")
defer src.Close()
dst, _ := os.Create("out.zip")
defer dst.Close()
io.Copy(dst, src) // สตรีม ไม่โหลดทั้งก้อนอย่า ReadAll ไฟล์ 1GB (แรมระเบิด) ให้อ่านทีละบรรทัด:
f, _ := os.Open("big.log")
defer f.Close()
sc := bufio.NewScanner(f)
sc.Buffer(make([]byte, 1024*1024), 10*1024*1024) // เผื่อบรรทัดยาว
for sc.Scan() {
line := sc.Text()
// ประมวลผลทีละบรรทัด
}
if err := sc.Err(); err != nil { log.Println(err) }เขียนบัฟเฟอร์ + Flush:
ไฟล์ยักษ์ + JSON ใช้ jsontext (ใหม่ 1.27) สตรีมทีละ token แทนโหลดทั้งก้อน (ดูเล่ม testing-http ประกอบ)
// เดินทั้งต้น
filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
if err != nil { return err }
fmt.Println(path)
return nil
})
filepath.Join("a", "b", "c.txt") // ต่อ path ถูกทุก OS
filepath.Ext("a.jpg") // .jpg
os.MkdirAll("data/2026", 0755)ฝังไฟล์ใน binary ด้วย embed (config/templ เล็กๆ):
Close -> fd รั่ว เปิดเยอะๆ พัง (ใช้ defer + linter ช่วย)"a\\b" ตรงๆ พังบน Linux/Mac ให้ใช้ filepath.Joinfilepath.Clean + ล็อกไม่ให้ ../ หลุดออกนอก (path traversal)0644 ไฟล์ 0755 โฟลเดอร์ อย่า 0777 มั่วgo vet จับ print/scan ผิดได้อ้างอิง: Effective Go #data, std os io bufio filepath embed
f, _ := os.Open("big.log")
defer f.Close()
sc := bufio.NewScanner(f)
sc.Buffer(make([]byte, 64*1024), 10*1024*1024) // บรรทัดยาวเกิน 64K ต้องขยาย
for sc.Scan() {
handle(sc.Text())
}
if err := sc.Err(); err != nil { // เช็กหลัง loop เสมอ
log.Fatal(err)
}f, _ := os.Open("app.zip")
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("%x\n", h.Sum(nil))defer Close() ทันทีบรรทัดถัดไป อย่ารอReadFile ทั้งก้อน ใช้สตรีม (Scanner/Copy)Clean + กัน ../ หลุดโฟลเดอร์ (path traversal)filepath.Join อย่าต่อ \ หรือ / เอง (พังข้าม OS)0644 โฟลเดอร์ 0755 ไม่ใช้ 0777 มั่วsc.Err() หลัง loop เสมอ ไม่งั้น error เงียบClose = fd รั่ว เปิดเยอะๆ พัง (ใช้ defer + linter ช่วย)