Go 操作 數據庫、Redis、HDFS


楔子

這里我們來介紹一下如何使用 Go 連接數據庫、Redis、HDFS,當然數據庫、Redis、HDFS本身我們就不介紹了,這里我們主要介紹如何使用 Go 進行連接並執行相應操作。

Go 操作數據庫

對於許多Web應用程序而言,數據庫都是其核心所在,數據庫幾乎可以用來存儲你想查詢和修改的任何信息。

但是Go本身沒有內置任何的驅動來操作數據庫,但是 Go 內置 database/sql,里面定義了一些接口,用於可以根據接口開發相應數據庫的驅動。比如:MySQL、PostgreSQL是不同的數據庫,但是我們都可以使用 database/sql 進行操作。常見的數據庫驅動如下:

  • Mysql: https://github.com/go-sql-driver/mysql
  • MyMysql: https://github.com/ziutek/mymysql
  • Postgres: https://github.com/lib/pq
  • Tidb: https://github.com/pingcap/tidb
  • SQLite: https://github.com/mattn/go-sqlite3
  • MsSql: https://github.com/denisenkom/go-mssqldb
  • Oracle: https://github.com/mattn/go-oci8

這里我們就使用PostgreSQL進行演示。

連接數據庫

要想使用Go操作PostgreSQL,那么首先要和數據庫之間建立連接,得到DB對象。

import (
    "database/sql"
    _ "github.com/lib/pq"
)

database/sql 是 Go 的標准庫之一,它提供了一系列接口方法,用於訪問關系數據庫。它並不會提供數據庫特有的方法,那些特有的方法會交給具體的數據庫驅動去實現。

我們正在加載的驅動是匿名的,導入之后該驅動會自行初始化並注冊到 Go 的 database/sql 上下文中,因此我們就可以 database/sql 包提供的方法去訪問數據庫了。

下面是建立連接,建立連接的話使用 sql.Open 函數:

func Open(driverName, dataSourceName string) (*DB, error) {
    /*
    driverName: 這個名字就是數據庫驅動注冊到 database/sql 時所使用的名字
    		   如果是MySQL數據庫的話, 那么就是"mysql"; 如果是PostgreSQL數據庫的話, 那么就是"postgres";
    dataSourceName: 數據庫的連接信息, 這個連接包括了數據庫的用戶名、密碼、數據庫主機以及連接的數據庫名等信息
    			   用戶名:密碼@協議(地址:端口)/數據庫?參數=參數值
    			   
    db, err := sql.Open("postgres", "postgres:zgghyys123@tcp(localhost:5432)/postgres")
    */
}

代碼演示一下:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

func main() {
    // 這里的open函數只是驗證參數是否合法, 不會創建和數據庫的連接; 得到的僅僅是一個sql.DB對象, 當進行數據庫查詢的時候才會建立網絡連接
    // sql.DB 表示操作數據庫的抽象接口, 但不是所謂的數據庫連接對象, 它只有在需要使用時才會創建連接
    // 注意: dataSourceName結尾的 sslmode=disable, 如果沒有的話會報錯: pq: SSL is not enabled on the server
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    // 記得關閉連接, 這里使用defer, 由於該函數返回一個error, 所以我們放在匿名函數中
    defer func() {_ = db.Close()}()

    // 如果要立刻檢測數據庫源是否能連接到指定的數據庫, 需要調用返回值的Ping方法
    fmt.Println(db.Ping()) // <nil>
    // 打印nil證明沒有錯誤
}

接下來就可以進行操作了,不過我們還可以設置連接數:

func (db *DB) SetMaxOpenConns(n int)
// SetMaxOpenConns表示設置與數據庫建立連接的最大數目
// 如果n大於0且小於最大閑置連接數, 會將最大閑置連接數減小到和最大開啟連接數相等
// 如果n<=0, 不會限制最大開啟連接數, 默認為0(無限制)

func (db *DB) SetMaxIdleConns(n int)
// SetMaxIdleConns設置連接池中的最大閑置連接數
// 如果n大於最大開啟連接數, 則會將新的最大閑置連接數會減小到和最大開啟連接數相等
// 如果n<=0, 不會保留閑置連接

個人覺得這兩個設置連接數,基本很少用,使用默認的即可。

增刪改查

下面就是喜聞樂見的增刪改查環節了,說是增刪改查,其實說白了還是體現在sql語句上。Go 的話,則只是一個連接、執行的過程。

查詢單條數據:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

type staff struct {
    name string
    status string
    // 由於數據庫字段名 type 和 Go 關鍵字沖突, 所以這里采用首字母大寫的形式
    // 首字母大小寫無影響
    Type string
    month int64
}
func main() {
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer func() {_ = db.Close()}()

    var s staff
    //這里的$1表示占位符
    query := "select * from staff where month = $7"
    //QueryRow查詢單條數據
    row := db.QueryRow(query, 7)
    // 調用 row.Scan 將結果賦值給結構體成員
    if err := row.Scan(&s.name, &s.status, &s.Type, &s.month); err != nil {
        panic(err)
    }
    // 注意: 如果查詢不到的話, 那么調用Scan會報錯, 因此這里錯誤實際上不應該拋出的
    fmt.Println(row)
}

查詢多條數據:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

type staff struct {
    name string
    status string
    Type string
    month int64
}
func main() {
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer func() {_ = db.Close()}()

    var s staff
    query := "select * from staff where month = $1"
    //只需要把QueryRow換成Query就可以了, 但是返回值會多出一個 error
    rows, err := db.Query(query, 7)
    if err != nil {
        panic(err)
    }
    // 然后通過循環直接獲取
    for rows.Next() {
        if err := rows.Scan(&s.name, &s.status, &s.Type, &s.month); err != nil {
            panic(err)
        } else {
            fmt.Println(s)
            /*
            {劉秀珍 完成 文件管理 7}
            {王亮 完成 文件管理 7}
            {胡秀華 未完成 文件管理 7}
            {胡秀華 完成 質量安全 7}
            {王亮 完成 文件管理 7}
            {王亮 未完成 班組建設 7}
            {林晨 完成 現場推演 7}
            */
        }
    }
}

除此之外我們在查詢的時候還可以獲取字段名,以及相應的字段屬性。

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

func main() {
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer func() {_ = db.Close()}()

    query := "select * from staff where month = $1"
    rows, err := db.Query(query, 7)
    if err != nil {
        panic(err)
    }

    columns, _ := rows.Columns()
    fmt.Println("字段名:", columns)  // 字段名: [name status type month]

    // 還可以獲取字段屬性
    /*
    column_types, _ := rows.ColumnTypes()
    for _, col_type := range column_types {
        // 可查看的屬性可以通過源代碼查看
    }
    */
}

插入數據:

插入、更新和刪除操作都使用相同的方法。

func (db *DB) Exec(query string, args ...interface{}) (Result, error)

可以直接調用 db.Exec 進行操作。

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

func main() {
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer func() {_ = db.Close()}()

    query := "insert into staff(status, month) values ($1, $2)"

    res, err := db.Exec(query, "完成", 8)
    if err != nil {
        panic(err)
    }

    // 返回插入的記錄id, 但是報錯; 這個driver不支持, 但mysql是支持的
    if id, err := res.LastInsertId(); err!=nil {
        fmt.Println(err)  // LastInsertId is not supported by this driver
    } else {
        fmt.Println(id)
    }

    //返回影響的行數
    if count, err := res.RowsAffected(); err!=nil {
        fmt.Println(err)
    } else {
        fmt.Println(count)  // 1
    }
}

更新數據和刪除數據也是同理,這里不贅述了。

預處理

1. 什么是預處理?

普通SQL語句執行過程:

  • 客戶端對SQL語句進行占位符替換得到完整的SQL語句

  • 客戶端發送完整SQL語句到數據庫服務端

  • 數據庫服務端執行完整的SQL語句並將結果返回給客戶端

預處理執行過程:

  • 把SQL語句分成兩部分,命令部分與數據部分

  • 先把命令部分發送給數據庫服務端,數據庫服務端進行SQL預處理

  • 然后把數據部分發送給數據庫服務端,數據庫服務端對SQL語句進行占位符替換

  • 數據庫服務端執行完整的SQL語句並將結果返回給客戶端

2. 為什么要預處理?

1. 優化MySQL服務器重復執行SQL的方法,可以提升服務器性能,提前讓服務器編譯,一次編譯多次執行,節省后續編譯的成本。

2. 避免SQL注入問題。

3. Go實現預處理

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

func main() {
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer func() {_ = db.Close()}()

    //Prepare方法會先將sql語句發送給數據庫服務端, 返回一個准備好的狀態用於之后的查詢和命令, 返回值可以同時執行多個查詢和命令。
    query := "insert into staff(status, month) values ($1, $2)"
    stmt, _ := db.Prepare(query)
    defer func() {_ = stmt.Close()}()

    // 傳入參數, 這里就不需要query了, 直接傳遞占位符對應的值即可
    res, _ := stmt.Exec("未完成", 9)
    count, _ := res.RowsAffected()
    fmt.Println(count)  // 1

    // 當然這里可以執行多次Exec, 傳入不同的參數
    res, _ = stmt.Exec("未完成", 10)
    count, _ = res.RowsAffected()
    fmt.Println(count)  // 1
}

Go實現數據庫事務

1. 什么是事務?

事務:一個最小的不可再分的工作單元;通常一個事務對應一個完整的業務(例如銀行賬戶轉賬業務,該業務就是一個最小的工作單元),同時這個完整的業務需要執行多次的DML(insert、update、delete)語句共同聯合完成。A轉賬給B,這里面就需要執行兩次update操作。

在MySQL中只有使用了Innodb數據庫引擎的數據庫或表才支持事務。事務處理可以用來維護數據庫的完整性,保證成批的SQL語句要么全部執行,要么全部不執行。

2. 事務的ACID

通常事務必須滿足4個條件(ACID):原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)。

3. 事務相關方法

Go語言中使用以下三個方法實現MySQL中的事務操作。

  • 開始事務

     func (db *DB) Begin() (*Tx, error)
    
  • 提交事務

     func (tx *Tx) Commit() error
    
  • 回滾事務

     func (tx *Tx) Rollback() error
    

4. 事務示例

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
)

func main() {
    db, err := sql.Open("postgres", "postgres://postgres:zgghyys123@127.0.0.1:5432/postgres?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer func() {_ = db.Close()}()

    // 開啟事務
    tx, err := db.Begin()
    if err != nil {
        panic(err)
    }
    query1 := "insert into staff(status, month) values ($1, $2)"
    tx.Exec(query1, "完成", 9)
    tx.Exec(query1, "未完成", 10)
    tx.Exec(query1, "完成", 11)

    //提交事務
    if err = tx.Commit(); err != nil {
        // 失敗了則進行回滾
        tx.Rollback()
        panic(err)
    }  
    fmt.Println("事務完成")  // 事務完成
}

SQL中的占位符

不同的數據庫中,SQL語句使用的占位符語法不盡相同。

Go 操作Redis

Go 操作Redis需要使用第三方庫,這里我們使用的第三方庫是 https://github.com/go-redis/redis,Star數比較高的一個庫。

首先是連接,Client對象是和Redis協作的主要接口,可以使用NewClient進行創建。

client := redis.NewClient(&redis.Options{
        Addr:     "47.94.174.89:6379",
        Password: "", // 無密碼
        DB:       0,  // 使用 0 號數據庫
    })

有了 client,那么便可以對Redis進行操作了,里面定義了大量的方法,和Redis命令是對應的。熟悉Redis的話,那么看源碼以及注釋完全可以直接上手操作。

package main

import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
)

func main() {
    client := redis.NewClient(&redis.Options{
        Addr:     "xx.xx.xx.xx:6379",
        Password: "", // 無密碼
        DB:       0,  // 使用 0 號數據庫
    })
    ctx := context.Background()

    client.Set(ctx, "name", "夏色祭", 0)
    val, err := client.Get(ctx, "name").Result()
    // 如果key不存在的話, 那么err == redis.Nil
    if err != redis.Nil {
        fmt.Println(val)  // 夏色祭
    }
}

這里可以自己嘗試操作一下,不再贅述了,比較簡單。因為Redis本身比較簡單,而且Go提供的API和Redis命令之間也是具有很高的相似度的。

Go 操作HDFS

HDFS指的是Hadoop的分布式文件存儲系統,Go 也是可以對其進行操作的,我們來看一下。

首先是安裝操作HDFS的第三方庫,直接go get github.com/vladimirvivien/gowfs即可

讀取文件

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
    "io/ioutil"
)

func main() {
    //這是配置,傳入Addr: "ip: 50070", User: "隨便寫一個英文名就行"
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    //返回一個客戶端(這里面叫文件系統)和error
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:",err))
    }

    //這里不能直接傳入文件名,而是需要作為gowfs.Path結構體的Name參數的值
    //然后將Path傳進去,我們后面的api都是這樣做的
    path := gowfs.Path{Name:"/whitealbum.txt"}

    //接收如下參數:gowfs.Path,offset(偏移量),長度(顯然是字節的長度), 容量(自己的cap)
    //返回一個io.ReadCloser,這是需要實現io.Reader和io.Closer的接口
    reader, _ := client.Open(path, 0, 512, 2048)

    //可以使用reader.Read(buf)的方式循環讀取,也可以丟給ioutil。ReadAll,一次性全部讀取
    data, _ := ioutil.ReadAll(reader)
    fmt.Println(string(data))
    /*
    	白色相簿什么的,已經無所謂了。
    	因為已經不再有歌,值得去唱了。
    	傳達不了的戀情,已經不需要了。
    	因為已經不再有人,值得去愛了。
    */
}

查看目錄有哪些內容

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name: "/"}
    // 返回[]FileStatus和error
    //這個FileStatus是什么?我們看一下源碼
    /*
    	type FileStatus struct {
    		AccesTime        int64  訪問時間
    		BlockSize        int64  塊大小,只針對文件(134217728 Bytes,128 MB),目錄的話為0
    		Group            string 所屬組
    		Length           int64  文件的字節數(目錄為0)
    		ModificationTime int64  修改時間
    		Owner            string 所有者
    		PathSuffix       string 文件后綴,說白了就是文件名
    		Permission       string 權限
    		Replication      int64  副本數
    		Type             string 類型,文本的話是FILE,目錄的話是DIRECTORY
    	}
    */
    fs_arr, _ := client.ListStatus(path)
    fmt.Println(fs_arr)
    // [{0 0 supergroup 0 1570359570447 dr.who tkinter 755 0 DIRECTORY} {0 134217728 supergroup 184 1570359155457 root whitealbum.txt 644 1 FILE}]

    for _, fs := range fs_arr {
        fmt.Println("文件名:", fs.PathSuffix)
        /*
        	文件名: tkinter
        	文件名: whitealbum.txt
        */
    }

    //FileStatus里面包含了文件的詳細信息,如果想查看某個文件的詳細信息
    //可以使用fs, err := client.GetFileStatus(path)
}

創建文件

package main

import (
    "bytes"
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name: "/黑色相簿.txt"}

    /*
    	Create函數接收如下參數。
    	data:io.Reader,一個實現了io.Reader接口的struct
    	Path:很簡單,就是我們這里的path
    	overwrite:是否覆蓋,如果為false表示不覆蓋,那么要求文件不能存在,否則報錯
    	blocksize:塊大小
    	replication:副本
    	permission:權限
    	buffersize:緩存大小
    	contenttype:內容類型

    	返回一個bool和error
    */
    if flag, err :=client.Create(
        bytes.NewBufferString("這是黑色相簿,不是白色相簿"), //如果不指定內容,就直接bytes.NewBufferString()即可
        path, //路徑
        false,//不覆蓋
        0,
        0,
        0666,
        0,
        "text/html",  //純文本格式
    ); err != nil {
        fmt.Println("創建文件出錯,錯誤為:", err)
    } else {
        fmt.Println("創建文件成功, flag =", flag)  //創建文件成功, flag = true
    }
}

查看一下

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
    "io/ioutil"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name: "/黑色相簿.txt"}

    reader , _ := client.Open(path, 0, 512, 2048)
    data, _ := ioutil.ReadAll(reader)
    fmt.Println(string(data)) // 這是黑色相簿,不是白色相簿
}

創建目錄

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name: "/a/b/c"}

    //遞歸創建
    flag, err := client.MkDirs(path, 0666)
    fmt.Println(flag) // true

    fs_arr, _ := client.ListStatus(gowfs.Path{Name:"/"})
    for _, fs := range fs_arr{
        fmt.Println(fs.PathSuffix)
        /*
        	黑色相簿.txt
        	a
        	tkinter
        	whitealbum.txt
        */
    }
}

重命名

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    fs_arr, _ := client.ListStatus(gowfs.Path{Name:"/"})
    for _, fs := range fs_arr{
        fmt.Println(fs.PathSuffix)
        /*
        	黑色相簿.txt
        	a
        	tkinter
        	whitealbum.txt
        */
    }

    flag, err := client.Rename(gowfs.Path{Name:"/黑色相簿.txt"}, gowfs.Path{Name:"/blackalbum.txt"})
    fmt.Println(flag) // true
    fs_arr, _ = client.ListStatus(gowfs.Path{Name:"/"})
    for _, fs := range fs_arr{
        fmt.Println(fs.PathSuffix)
        /*
        	a
        	blackalbum.txt
        	tkinter
        	whitealbum.txt
        */
    }
}

向已經存在的文件追加內容

package main

import (
    "bytes"
    "fmt"
    "github.com/vladimirvivien/gowfs"
    "io/ioutil"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name: "/whitealbum.txt"}
    reader, _ := client.Open(path, 0, 512, 2048)
    data, _ := ioutil.ReadAll(reader)
    fmt.Println(string(data))
    /*
    	白色相簿什么的,已經無所謂了。
    	因為已經不再有歌,值得去唱了。
    	傳達不了的戀情,已經不需要了。
    	因為已經不再有人,值得去愛了。
    */

    //參數1:內容,必須是實現了io.Reader接口
    //參數2:路徑
    //參數3:緩存大小
    flag, err := client.Append(bytes.NewBufferString("\n讓人討厭的冬天又來了"), path, 2048)
    fmt.Println(flag) // true

    reader, _ = client.Open(path, 0, 512, 2048)
    data, _ = ioutil.ReadAll(reader)
    fmt.Println(string(data))
    /*
    	白色相簿什么的,已經無所謂了。
    	因為已經不再有歌,值得去唱了。
    	傳達不了的戀情,已經不需要了。
    	因為已經不再有人,值得去愛了。

    	讓人討厭的冬天又來了。
    */
}

設置文件或目錄的所有者

func (fs *FileSystem) SetOwner(path Path, owner string, group string) (bool, error)

設置文件或目錄的權限

func (fs *FileSystem) SetPermission(path Path, permission os.FileMode) (bool, error)

設置文件或目錄的副本系數

func (fs *FileSystem) SetReplication(path Path, replication uint16) (bool, error)

設置文件或目錄的訪問時間和修改時間

func (fs *FileSystem) SetTimes(path Path, accesstime int64, modificationtime int64) (bool, error)

獲取文件的校驗和

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name: "/whitealbum.txt"}
    f, _ := client.GetFileChecksum(path)
    fmt.Println(f)  // {MD5-of-0MD5-of-512CRC32C 0000020000000000000000001255073187d3e801940eee180acebe4e00000000 28}
    fmt.Println(f.Algorithm, f.Length, f.Bytes) // MD5-of-0MD5-of-512CRC32C 28 0000020000000000000000001255073187d3e801940eee180acebe4e00000000
}

刪除文件

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    path := gowfs.Path{Name:"/blackalbum.txt"}
    //路徑,是否遞歸
    flag, _ := client.Delete(path, true)
    fmt.Println(flag) // true
}

判斷文件是否存在

為什么這里用藍色了,因為之后的用法就不一樣了

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, err := gowfs.NewFileSystem(config)
    if err != nil {
        panic(fmt.Sprintln("出現異常,異常信息為:", err))
    }

    //創建一個shell,可以使用下面shell進行操作
    shell := gowfs.FsShell{FileSystem: client}

    //直接傳字符串即可,不需要傳Path了
    flag, _ := shell.Exists("/whitealbum.txt")
    fmt.Println(flag) // true
    flag, _ = shell.Exists("/whitealbum.txt1")
    fmt.Println(flag) // false
}

改變所有者

flag, _ := shell.Chown([]string{"/file1", "/file2", "/file3"}, "owner")

改變所屬組

flag, _ := shell.Chgrp([]string{"/file1", "/file2", "/file3"}, "groupName")

改變權限

flag, _ := shell.Chmod([]string{"/file1", "/file2", "/file3"}, 0666)

查看文件內容

package main

import (
    "bytes"
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, _ := gowfs.NewFileSystem(config)

    shell := gowfs.FsShell{FileSystem: client}

    buf := bytes.Buffer{}
    if err := shell.Cat([]string{"/whitealbum.txt"}, &buf); err != nil {
        fmt.Println("err =", err)
    } else {
        fmt.Println(buf.String())
        /*
        	白色相簿什么的,已經無所謂了。
        	因為已經不再有歌,值得去唱了。
        	傳達不了的戀情,已經不需要了。
        	因為已經不再有人,值得去愛了。

        	讓人討厭的冬天又來了
        */
    }
}

追加文件內容

package main

import (
    "bytes"
    "fmt"
    "github.com/vladimirvivien/gowfs"
    "io/ioutil"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, _ := gowfs.NewFileSystem(config)

    shell := gowfs.FsShell{FileSystem: client}

    _ = ioutil.WriteFile("aaa.txt", []byte("\n冬馬小三\n"), 0666)
    _ = ioutil.WriteFile("bbb.txt", []byte("雪菜碧池\n"), 0666)
    _ = ioutil.WriteFile("ccc.txt", []byte("打死春哥\n"), 0666)
    _ = ioutil.WriteFile("ddd.txt", []byte("抱走冬馬雪菜"), 0666)

    _, _ = shell.AppendToFile([]string{"aaa.txt", "bbb.txt", "ccc.txt", "ddd.txt"}, "/whitealbum.txt")

    buf := bytes.Buffer{}
    _ = shell.Cat([]string{"/whitealbum.txt"}, &buf)
    fmt.Println(buf.String())
    /*
    	白色相簿什么的,已經無所謂了。
    	因為已經不再有歌,值得去唱了。
    	傳達不了的戀情,已經不需要了。
    	因為已經不再有人,值得去愛了。

    	讓人討厭的冬天又來了
    	冬馬小三
    	雪菜碧池
    	打死春哥
    	抱走冬馬雪菜
    */
}

上傳文件

package main

import (
    "fmt"
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, _ := gowfs.NewFileSystem(config)

    shell := gowfs.FsShell{FileSystem: client}

    //本地路徑,hdfs路徑,是否重寫
    _, _ = shell.Put("aaa.txt", "/aaa.txt", false)

    path := gowfs.Path{Name: "/"}
    fs_arr, _ := client.ListStatus(path)
    for _, fs := range fs_arr {
        fmt.Println(fs.PathSuffix)
        /*
        	黑色相簿.txt
        	a
        	aaa.txt
        	tkinter
        	whitealbum.txt
        */
    }
}

下載文件

package main

import (
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, _ := gowfs.NewFileSystem(config)

    shell := gowfs.FsShell{FileSystem: client}

    _, _ = shell.Get("/whitealbum.txt", "白色album.txt")
}

刪除文件

package main

import (
    "github.com/vladimirvivien/gowfs"
)

func main() {
    config := gowfs.Configuration{Addr: "xx.xx.xx.xx:50070", User: "satori"}
    client, _ := gowfs.NewFileSystem(config)

    shell := gowfs.FsShell{FileSystem: client}

    _, _ = shell.Rm("/whitealbum.txt")
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM