July 25th, 2023

Announcing the stable release of the Azure Files client library for Go

Sourav Gupta
Software Engineer

The Azure SDK for Go team at Microsoft is excited to announce the stable release of the Azure Files client library for Go. Azure Files offers fully managed file shares in the cloud that are accessible via the industry standard Server Message Block (SMB) protocol. Azure Files shares can be mounted concurrently by cloud or on-premises deployments of Windows, Linux, and macOS. Azure Files shares can also be cached on Windows Servers with Azure File Sync for fast access near where the data is being used.

To upgrade from the legacy Azure Files library for Go, see the migration guide.

Install the package

The Azure Files client library is named azfile. To install the latest version of azfile, use the following go get command:

go get github.com/Azure/azure-sdk-for-go/sdk/storage/azfile

We assume that you have:

  • An Azure subscription.
  • A working development environment for Go version 1.18 or above.

Create a client

Client is a type that exposes methods that invoke service operations. A Client type is shareable between multiple goroutines simultaneously and safely.

Azure Files offers four types of resources: the storage account, the shares within the account, and the directories and files within a share. Instances of the service.Client, share.Client, directory.Client, and file.Client types provide methods to manipulate shares, directories, and files within a storage account. You must specify the storage account when you create a client.

You can create a client using an Azure Files connection string or access key or with a Shared Access Signature(SAS) (obtained via the Azure portal).

Use Azure Files connection string

Azure Files supports authentication using a connection string, which you can get from the Azure portal.

package main

import "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service"

func main() {
    serviceClient, err := service.NewClientFromConnectionString("<Azure Storage Connection String>", nil)
    if err != nil {
        //TODO: handle error
        panic(err)
    }
}

Use the SharedKeyCredential

Azure Files supports authentication using access key, which you can get from the Azure portal.

package main

import "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service"

func main() {
    // create a credential for authenticating using shared key
    cred, err := service.NewSharedKeyCredential("<my-storage-account-name>", "<my-storage-account-key>")
    if err != nil {
        //TODO: handle error
        panic(err)
    }

    // create service.Client for the specified storage account that uses the above credential
    serviceClient, err := service.NewClientWithSharedKeyCredential("https://<my-storage-account-name>.file.core.windows.net/", cred, nil)
    if err != nil {
        //TODO: handle error
        panic(err)
    }
}

Use the Shared Access Signature (SAS) token

Azure Files supports authentication using SAS token, which you can get from the Azure portal.

package main

import "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/service"

func main() {
    serviceClient, err := service.NewClientWithNoCredential("https://<my-storage-account-name>.file.core.windows.net/?<sas token>", nil)
    if err != nil {
        //TODO: handle error
        panic(err)
    }
}

Share operations

The share.Client type exposes share operations that manipulate the lifecycle of the Azure Files share.

Create a share

The share package’s Create method creates a new share under the specified account. If a share with the same name already exists, the method call raises a ResourceAlreadyExists error.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/share"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_NAME could not be found")
    }
    accountKey, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_KEY")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_KEY could not be found")
    }

    shareName := "testshare"
    shareURL := fmt.Sprintf("https://%s.file.core.windows.net/%s", accountName, shareName)

    cred, err := share.NewSharedKeyCredential(accountName, accountKey)
    handleError(err)

    shareClient, err := share.NewClientWithSharedKeyCredential(shareURL, cred, nil)
    handleError(err)

    _, err = shareClient.Create(context.TODO(), nil)
    handleError(err)
}

Delete a share

The share package’s Delete method is a share lifecycle method that marks the specified share for deletion. During garbage collection, Azure deletes the share and any directories/files within it. If the share is missing, the method call raises a ResourceNotFound error.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/share"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_NAME could not be found")
    }
    accountKey, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_KEY")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_KEY could not be found")
    }

    shareName := "testshare"
    shareURL := fmt.Sprintf("https://%s.file.core.windows.net/%s", accountName, shareName)

    cred, err := share.NewSharedKeyCredential(accountName, accountKey)
    handleError(err)

    shareClient, err := share.NewClientWithSharedKeyCredential(shareURL, cred, nil)
    handleError(err)

    _, err = shareClient.Delete(context.TODO(), nil)
    handleError(err)
}

Directory operations

The directory.Client type exposes operations that can be performed on directories in a file share.

Create a directory

The directory package’s Create method creates a new directory under the specified share. If a directory with the same name already exists, the method call raises a ResourceAlreadyExists error.

package main

import (
    "context"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/directory"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    connectionString, ok := os.LookupEnv("AZURE_STORAGE_CONNECTION_STRING")
    if !ok {
        panic("AZURE_STORAGE_CONNECTION_STRING could not be found")
    }
    shareName := "testShare"
    dirName := "testDirectory"
    dirClient, err := directory.NewClientFromConnectionString(connectionString, shareName, dirName, nil)
    handleError(err)

    _, err = dirClient.Create(context.Background(), nil)
    handleError(err)
}

Delete a directory

The directory package’s Delete method deletes the specified empty directory. If you attempt to delete directories that aren’t empty, the method call raises a DirectoryNotEmpty error. If the directory is missing, the method call raises a ResourceNotFound error.

package main

import (
    "context"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/directory"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    connectionString, ok := os.LookupEnv("AZURE_STORAGE_CONNECTION_STRING")
    if !ok {
        panic("AZURE_STORAGE_CONNECTION_STRING could not be found")
    }
    shareName := "testShare"
    dirName := "testDirectory"
    dirClient, err := directory.NewClientFromConnectionString(connectionString, shareName, dirName, nil)
    handleError(err)

    _, err = dirClient.Delete(context.Background(), nil)
    handleError(err)
}

File operations

The file.Client type exposes the operations that interact with the files that reside inside the Azure Files share or directory.

Upload file to a directory

The UploadFile method uploads a file in chunks to a file inside the Azure Files share or directory. This operation can be performed on an existing file only, otherwise it raises a ResourceNotFound error.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    // Set up file to upload
    fileSize := 8 * 1024 * 1024
    fileName := "test_upload_file.txt"
    fileData := make([]byte, fileSize)
    err := os.WriteFile(fileName, fileData, 0666)
    handleError(err)

    // Open the file to upload
    fileHandler, err := os.Open(fileName)
    handleError(err)

    // delete the local file if required.
    defer func(name string) {
        err = os.Remove(name)
        handleError(err)
    }(fileName)

    // close the file after it is no longer required.
    defer func(fh *os.File) {
        err = fh.Close()
        handleError(err)
    }(fileHandler)

    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_NAME could not be found")
    }
    accountKey, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_KEY")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_KEY could not be found")
    }

    cred, err := file.NewSharedKeyCredential(accountName, accountKey)
    handleError(err)

    shareName := "testShare"
    dirName := "testDirectory"

    fileURL := fmt.Sprintf("https://%s.file.core.windows.net/%s/%s/%s", accountName, shareName, dirName, fileName)
    fileClient, err := file.NewClientWithSharedKeyCredential(fileURL, cred, nil)
    handleError(err)

    _, err = fileClient.Create(context.Background(), int64(fileSize), nil)
    handleError(err)

    err = fileClient.UploadFile(context.Background(), fileHandler, nil)
    handleError(err)
}

Download file from a directory

DownloadFile downloads a file from the Azure Files share or directory to a local file that is passed as a parameter. If the size doesn’t match, the method truncates the destination file.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    // Set up file to download to
    destFileName := "test_download_file.txt"
    destFile, err := os.Create(destFileName)
    handleError(err)
    defer func(destFile *os.File) {
        err = destFile.Close()
        handleError(err)
    }(destFile)

    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_NAME could not be found")
    }
    accountKey, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_KEY")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_KEY could not be found")
    }

    cred, err := file.NewSharedKeyCredential(accountName, accountKey)
    handleError(err)

    shareName := "testShare"
    dirName := "testDirectory"

    fileURL := fmt.Sprintf("https://%s.file.core.windows.net/%s/%s/%s", accountName, shareName, dirName, destFileName)
    fileClient, err := file.NewClientWithSharedKeyCredential(fileURL, cred, nil)
    handleError(err)

    _, err = fileClient.DownloadFile(context.Background(), destFile, nil)
    handleError(err)
}

Delete file in a directory

The file package’s Delete method immediately removes the file from the storage account. For more information, see the delete file documentation.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/Azure/azure-sdk-for-go/sdk/storage/azfile/file"
)

func handleError(err error) {
    if err != nil {
        log.Fatal(err.Error())
    }
}

func main() {
    accountName, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_NAME")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_NAME could not be found")
    }
    accountKey, ok := os.LookupEnv("AZURE_STORAGE_ACCOUNT_KEY")
    if !ok {
        panic("AZURE_STORAGE_ACCOUNT_KEY could not be found")
    }

    cred, err := file.NewSharedKeyCredential(accountName, accountKey)
    handleError(err)

    shareName := "testShare"
    dirName := "testDirectory"
    fileName := "testFile"

    fileURL := fmt.Sprintf("https://%s.file.core.windows.net/%s/%s/%s", accountName, shareName, dirName, fileName)
    fileClient, err := file.NewClientWithSharedKeyCredential(fileURL, cred, nil)
    handleError(err)

    _, err = fileClient.Delete(context.Background(), nil)
    handleError(err)
}

Summary

The Azure Files library for Go allows users to manipulate files, directories and shares in Azure Storage. To learn more, see our documentation. You can also find more examples either on pkg.go.dev or in our GitHub repository.

Feedback

We’d love to hear about your experiences using the Azure SDK for Go. Send us your feedback on our Slack Channel or at the #golang-friends channel on the Microsoft Open Source Discord Server.

For feature requests, bug reports, or general support, open an issue in the Azure SDK for Go repository on GitHub.

Author

Sourav Gupta
Software Engineer

0 comments

Discussion are closed.