I. Giới Thiệu về File I/O trong Ngôn Ngữ Go
Ngôn ngữ lập trình Go cung cấp nhiều package hữu ích để làm việc với file và I/O. Trong bài viết này, chúng ta sẽ khám phá các package quan trọng và cách sử dụng chúng qua nhiều ví dụ phong phú.
Package os
Package os
cung cấp giao diện cho các chức năng cơ bản của hệ điều hành, bao gồm việc quản lý file như tạo, đọc, ghi và xóa. Dưới đây là ví dụ đơn giản về việc tạo một file mới:
go
file, err := os.Create("data.txt")
if err != nil {
// Xử lý lỗi
}
defer file.Close()
Hãy cùng xem kỹ hàm Create
trong package os
:
go
func Create(name string) (*File, error) {
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}
Hàm này nhận vào một chuỗi name
đại diện cho tên (hoặc đường dẫn) của file cần tạo. Hàm OpenFile
sẽ trả về một pointer đến đối tượng File
và một giá trị error
. Các hằng số O_RDWR|O_CREATE|O_TRUNC
được dùng để định nghĩa cách mở file. Cụ thể:
O_RDWR
: Mở file để đọc và ghi.O_CREATE
: Tạo file nếu chưa tồn tại.O_TRUNC
: Cắt bỏ nội dung của file nếu file đã tồn tại.0666
: Quyền truy cập của file cho phép tất cả người dùng có thể đọc và ghi.
Chúng ta cũng có thể mở một file bằng cách sử dụng hàm Open
:
go
file, err := os.Open("data.txt")
if err != nil {
// Xử lý lỗi
}
defer file.Close()
Hàm Open
cũng gọi đến OpenFile
, nhưng sử dụng tham số O_RDONLY
, nghĩa là file sẽ chỉ được mở để đọc. Nếu file không tồn tại, OpenFile
sẽ trả về một lỗi.
Lưu ý: Đóng file bằng
file.Close()
giúp ngăn ngừa việc vượt quá giới hạn số lượng file được mở bởi hệ điều hành, đảm bảo rằng dữ liệu được ghi từ bộ đệm vào file, và tránh các lỗi khi các quá trình khác truy cập file.
Package io
Package io
cung cấp các giao diện cơ bản để đọc và ghi dữ liệu từ/đến các nguồn khác nhau, bao gồm cả file. Nó bao gồm các công cụ hữu ích như io.Reader
và io.Writer
.
Ví dụ 1: Sao Chép File
go
sourceFile, err := os.Open("source.txt")
if err != nil {
// Xử lý lỗi
}
defersourceFile.Close()
destFile, err := os.Create("dest.txt")
if err != nil {
// Xử lý lỗi
}
defer destFile.Close()
_, err = io.Copy(destFile, sourceFile)
if err != nil {
// Xử lý lỗi
}
Trong ví dụ này, chúng ta mở file nguồn source.txt
và tạo file đích dest.txt
rồi sử dụng hàm io.Copy
để sao chép dữ liệu từ file nguồn sang file đích.
Ví dụ 2: Đọc Nội Dung File
go
file, err := os.Open("data.txt")
if err != nil {
// Xử lý lỗi
}
data, err := io.ReadAll(file)
fmt.Println("Dữ liệu: ", string(data))
Đoạn mã này mở file data.txt
và đọc toàn bộ nội dung vào bộ nhớ. Tuy nhiên, phương pháp này có thể dẫn đến tình trạng lỗi tràn bộ nhớ khi file quá lớn. Hãy xem xét cách ReadAll
hoạt động:
Hàm ReadAll
đọc toàn bộ dữ liệu từ một Reader
vào một slice byte, tạo một slice với dung lượng ban đầu là 512
. Nếu slice đầy, nó sẽ tăng dung lượng cho tới khi đọc hết dữ liệu. Nếu file lớn (ví dụ: 10GB hoặc 1TB), cách này sẽ dẫn đến lỗi tràn bộ nhớ. Để khắc phục, chúng ta sẽ sử dụng package bufio
để đọc file theo từng phần.
go
file, err := os.Open("data.txt")
if err != nil {
// Xử lý lỗi
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println("Dữ liệu: ", scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Println("Lỗi: ", err)
}
Trong ví dụ này, chúng ta tạo một Scanner
để đọc file. Mỗi khi sử dụng phương thức Scan
để đọc từng dòng, chúng ta in ra nội dung. Nếu gặp lỗi, chúng ta có thể kiểm tra với scanner.Err()
.
II. Kết Luận
Qua bài viết này, chúng ta đã tìm hiểu về các package như os
, io
, và bufio
cho File I/O trong Go. Các package này giúp chúng ta quản lý file một cách hiệu quả, từ việc tạo file mới đến đọc và ghi dữ liệu. Cảm ơn các bạn đã theo dõi bài viết!
source: viblo