1. Cơ bản về Thư viện OS
Gói os
trong Golang cung cấp một giao diện độc lập với nền tảng cho các chức năng của hệ điều hành. Tiếp theo, chúng ta sẽ thảo luận về cách sử dụng gói os
để xử lý mở, đóng, đọc, ghi tập tin cũng như lấy và thiết lập thuộc tính của tập tin.
1.1 Mở và Đóng Tập Tin
Trong ngôn ngữ Go, bạn có thể sử dụng hàm os.Open
để mở một tập tin, nó sẽ trả về một đối tượng *os.File
và một lỗi. Sau khi tập tin được mở, bạn có thể thực hiện các hoạt động đọc, ghi và các hoạt động khác. Sau khi các hoạt động hoàn tất, bạn nên gọi file.Close
để đóng tập tin và giải phóng tài nguyên tương ứng.
Dưới đây là một ví dụ về việc mở một tập tin:
package main
import (
"fmt"
"os"
)
func main() {
// Mở tập tin test.txt trong thư mục hiện tại
file, err := os.Open("test.txt")
if err != nil {
// Xử lý lỗi khi mở tập tin
fmt.Println("Lỗi khi mở tập tin:", err)
return
}
// Sử dụng câu lệnh defer để đảm bảo tập tin sẽ được đóng cuối cùng
defer file.Close()
// Các hoạt động xử lý tập tin...
fmt.Println("Tập tin mở thành công")
}
Trong đoạn mã trên, chúng ta sử dụng câu lệnh defer
để đảm bảo rằng file.Close
sẽ được thực thi bất kể thế nào. Điều này là một thực hành phổ biến trong ngôn ngữ Go để dọn dẹp tài nguyên.
1.2 Các Hoạt Động Đọc và Ghi Tập Tin
Kiểu os.File
có các phương thức Read
và Write
, có thể được sử dụng cho các hoạt động đọc và ghi tập tin. Phương thức Read
đọc dữ liệu từ tập tin vào mảng byte, và phương thức Write
ghi dữ liệu từ mảng byte vào tập tin.
Ví dụ sau minh họa cách đọc và ghi vào tập tin:
package main
import (
"fmt"
"os"
)
func main() {
// Mở tập tin
file, err := os.OpenFile("test.txt", os.O_RDWR, 0644)
if err != nil {
fmt.Println("Lỗi khi mở tập tin:", err)
return
}
defer file.Close()
// Ghi nội dung vào tập tin
message := []byte("Xin chào, Gophers!")
_, writeErr := file.Write(message)
if writeErr != nil {
fmt.Println("Lỗi khi ghi vào tập tin:", writeErr)
return
}
// Đọc tập tin từ đầu
file.Seek(0, 0)
buffer := make([]byte, len(message))
_, readErr := file.Read(buffer)
if readErr != nil {
fmt.Println("Lỗi khi đọc tập tin:", readErr)
return
}
fmt.Println("Nội dung tập tin:", string(buffer))
}
Trong ví dụ này, chúng ta sử dụng os.OpenFile
thay vì os.Open
. Hàm os.OpenFile
cho phép bạn chỉ định chế độ và quyền khi mở tập tin. Trong ví dụ trên, chúng ta sử dụng cờ os.O_RDWR
, có nghĩa là tập tin sẽ được mở ở chế độ đọc ghi.
1.3 Thuộc tính và Quyền truy cập File
Bạn có thể sử dụng các hàm từ gói os
để truy cập và sửa đổi thông tin trạng thái của file. Sử dụng os.Stat
hoặc os.Lstat
để có được giao diện os.FileInfo
, cung cấp thông tin về file như kích thước, quyền truy cập, thời gian sửa đổi, và nhiều hơn nữa.
Dưới đây là một ví dụ về cách nhận thông tin trạng thái file:
package main
import (
"fmt"
"os"
)
func main() {
fileInfo, err := os.Stat("test.txt")
if err != nil {
fmt.Println("Lỗi khi lấy thông tin file:", err)
return
}
// In kích thước file
fmt.Printf("Kích thước file: %d bytes\n", fileInfo.Size())
// In quyền truy cập file
fmt.Printf("Quyền truy cập file: %s\n", fileInfo.Mode())
}
Nếu bạn cần đổi tên file hoặc sửa đổi quyền truy cập của file, bạn có thể sử dụng os.Rename
để đổi tên file hoặc os.Chmod
để thay đổi quyền truy cập của file.
package main
import (
"fmt"
"os"
)
func main() {
// Thay đổi quyền truy cập của file thành chỉ đọc
err := os.Chmod("test.txt", 0444)
if err != nil {
fmt.Println("Lỗi khi thay đổi quyền truy cập file:", err)
return
}
// Đổi tên file
renameErr := os.Rename("test.txt", "renamed.txt")
if renameErr != nil {
fmt.Println("Lỗi khi đổi tên file:", renameErr)
return
}
fmt.Println("Các thao tác file thành công")
}
Ở đây, chúng ta đổi quyền truy cập của file test.txt
thành chỉ đọc, sau đó đổi tên file thành renamed.txt
. Lưu ý rằng khi sửa đổi quyền truy cập file, cẩn thận vì cài đặt quyền truy cập không đúng có thể dẫn đến file không thể truy cập.
2. Cách sử dụng cơ bản của Thư viện IO
Trong ngôn ngữ Go, thư viện io
cung cấp các giao diện cơ bản cho các nguyên tắc I/O (các hoạt động nhập/ xuất). Thiết kế của thư viện io
tuân theo các nguyên tắc đơn giản và giao diện đồng nhất, cung cấp hỗ trợ cơ bản cho các loại hoạt động I/O khác nhau, như đọc/ghi file, giao tiếp mạng, đệm dữ liệu, và nhiều hơn nữa.
2.2 Sử dụng Giao diện Đọc (Reader) và Ghi (Writer)
io.Reader
và io.Writer
là hai giao diện cơ bản được sử dụng để chỉ định các hoạt động đọc và ghi của một đối tượng. Chúng được thực hiện bởi các loại khác nhau, như file, kết nối mạng và bộ đệm.
io.Reader
Giao diện io.Reader
có một phương thức Read:
Read(p []byte) (n int, err error)
Phương thức này đọc tối đa len(p)
byte dữ liệu từ io.Reader
vào p
. Nó trả về số byte đọc được n
(0 <= n
<= len(p
)) và bất kỳ lỗi nào gặp phải.
Đoạn mã mẫu:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Xin chào, Thế giới!")
buf := make([]byte, 4)
for {
n, err := r.Read(buf)
if err == io.EOF {
break
}
fmt.Printf("Số byte đọc: %d, Nội dung: %s\n", n, buf[:n])
}
}
Trong ví dụ này, chúng ta tạo một strings.NewReader
để đọc dữ liệu từ một chuỗi sau đó đọc dữ liệu theo từng khối 4 byte.
io.Writer
Giao diện io.Writer
có phương thức Write:
Write(p []byte) (n int, err error)
Phương thức này ghi dữ liệu từ p
vào luồng dữ liệu cơ bản, trả về số byte được ghi và bất kỳ lỗi nào gặp phải.
Đoạn mã mẫu:
package main
import (
"fmt"
"os"
)
func main() {
data := []byte("Xin chào, Thế giới!\n")
n, err := os.Stdout.Write(data)
if err != nil {
panic(err)
}
fmt.Printf("Số byte đã ghi: %d\n", n)
}
Ví dụ này ghi một chuỗi đơn giản vào đầu ra chuẩn os.Stdout
, đóng vai trò là một triển khai của io.Writer
.
2.3 Các Chức Năng Đọc/Viết Nâng Cao
Gói io
cung cấp một số chức năng nâng cao có thể giúp đơn giản hóa các nhiệm vụ thông thường, như việc sao chép dữ liệu và đọc một lượng dữ liệu cụ thể.
Chức Năng Sao Chép
io.Copy
là một phương pháp tiện lợi để sao chép trực tiếp dữ liệu từ một io.Reader
sang một io.Writer
mà không cần một bộ đệm trung gian.
Mã mẫu:
package main
import (
"io"
"os"
"strings"
)
func main() {
r := strings.NewReader("Ví dụ về thao tác sao chép đơn giản")
_, err := io.Copy(os.Stdout, r)
if err != nil {
panic(err)
}
}
Trong ví dụ này, chúng ta sao chép trực tiếp một chuỗi vào đầu ra tiêu chuẩn.
Chức Năng ReadAtLeast
Chức năng io.ReadAtLeast
được sử dụng để đảm bảo rằng ít nhất một lượng dữ liệu cụ thể được đọc từ một io.Reader
trước khi trả về.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
Mã mẫu:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Trang web Tiếng Trung về Ngôn Ngữ Go")
buf := make([]byte, 14)
n, err := io.ReadAtLeast(r, buf, 14)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s\n", buf[:n])
}
Trong ví dụ này, io.ReadAtLeast
cố gắng đọc ít nhất 14 byte dữ liệu vào buf
.
Các chức năng đọc/viết nâng cao này cho phép bạn xử lý các nhiệm vụ liên quan đến I/O một cách hiệu quả và cung cấp một nền tảng vững chắc để xây dựng logic chương trình phức tạp hơn.