Springboot + Azure File Storage 实现微软云读写共享文件

前言:最近公司接了个海外(新加坡)的ERP项目,其中有一个功能读取共享文件夹内的文件,折腾来折腾去总算搞出来之后又被客户方告知需要使用微软云的共享文件读写方式,因从未使用过微软云,所以特此记录下。分享给大家一起学习进步!

代码实现

非SpringBoot项目需要引入下面三个jar包:

1.azure-data-lake-store-sdk-2.1.5.jar 2.azure-storage-8.3.0.jar 3.azure-storage-blob-11.0.0.jar

1.pom.xml文件引入依赖

<!--Azure Blob Storage(微软云) 基本用法上传/下载-->
		<dependency>
			<groupId>com.microsoft.azure</groupId>
			<artifactId>azure-data-lake-store-sdk</artifactId>
			<version>2.1.5</version>
		</dependency>

		<dependency>
			<groupId>com.microsoft.azure</groupId>
			<artifactId>azure-storage-blob</artifactId>
			<version>11.0.0</version>
		</dependency>

		<dependency>
			<groupId>com.microsoft.azure</groupId>
			<artifactId>azure-storage</artifactId>
			<version>8.3.0</version>
		</dependency>

2.编写测试代码,方便测试所以都写在了同一个类

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.file.*;

import java.io.IOException;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 微软云Azure读写共享文件帮助类
 */
public class AzureUtil {

    private static String SHARE_FILE_NAME = "xxx";//需要读取数据共享文件夹名称--对应云盘中你需要读取文件的文件夹名称
    private static String SHARE_NEW_FILE_NAME = "xxx";//临时存放数据共享文件夹名称--这个是copy文件至新的路径使用的,如只需要copy到原地址则不需要改参数
    private static String SHARE_NAME = <Folder Name>;// 微软云共享云盘名称
    private static String ACCOUNT_NAME = <ACCOUNT NAME>;//<ACCOUNT NAME> 账号
    private static String ACCOUNT_KEY = <ACCOUNT KEY>;// 密码
    //注意连接字符串中的xxx和yyy,分别对应Access keys中的Storage account name 和 key。
    private static String format = "DefaultEndpointsProtocol=https;AccountName=" + ACCOUNT_NAME + ";AccountKey=" + ACCOUNT_KEY + "";

    private static CloudFileShare share;

    public static void main(String[] args) throws URISyntaxException, StorageException, IOException {
        //初始化
        initAzure(SHARE_NAME);
        //遍历共享文件夹下的文件
        getFileList();
    }

    /**
     * 初始化Azure
     * 获取连接
     *
     * @param shareName
     * @throws StorageException
     */
    public static void initAzure(String shareName) {
        //CloudStorageAccount 类表示一个 Azure Storage Account,我们需要先创建它的实例,才能访问属于它的资源。
        CloudStorageAccount storageAccount = null;
        try {
            // 获得StorageAccount对象
            storageAccount = CloudStorageAccount.parse(format);
            // 由StorageAccount对象创建CloudFileClient
            CloudFileClient fileClient = storageAccount.createCloudFileClient();
            // 获取对文件共享的引用   根据传入的contashareNameinerName, 获得share实例
            share = fileClient.getShareReference(shareName);
            //不存在则创建
//            if (share.createIfNotExists()) {
//                System.out.println("New share created");
//            }
        } catch (InvalidKeyException | URISyntaxException |StorageException invalidKey) {
            // Handle the exception
            invalidKey.printStackTrace();
        }
    }

    /**
     * 遍历共享文件夹下的文件
     *
     * @throws URISyntaxException
     * @throws StorageException
     */
    public static void getFileList() throws URISyntaxException, StorageException, IOException {
        //获取对共享根目录的引用。
        CloudFileDirectory rootDir = share.getRootDirectoryReference();

        //获取对包含该文件的目录的引用
        CloudFileDirectory sampleDir = rootDir.getDirectoryReference(SHARE_FILE_NAME);
        Iterable<ListFileItem> listFileItems = sampleDir.listFilesAndDirectories();
        for (ListFileItem listFileItem : listFileItems) {
            String fileName = listFileItem.getUri().getPath().split("/")[3];
            //获取要下载的文件的引用
            CloudFile file = sampleDir.getFileReference(fileName);

            //文件存在则复制到新路径
            if (!file.exists()) {
                System.err.println(file.getUri() + " 不存在");
                break;
            }
            //拼接文件名称
            String[] split = fileName.split("\\.");
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
            String newFileName = split[0] + "_" + sdf.format(new Date()) + "." + split[1];

            //复制文件至newFilePath,复制成功则删除原地址文件
            if (moveFile(fileName, newFileName)) {
                delFile(fileName);
            } else
                System.err.println("复制文件失败:" + listFileItem.getUri().getPath());

            //将文件的内容写入控制台。
//            System.out.println(file.downloadText());
        }
    }

    /**
     * 复制文件至新的路径
     *
     * @param fileName    文件名称
     * @param newFileName 复制到目标地址后文件名称
     */
    public static boolean moveFile(String fileName, String newFileName) {
        boolean flag = false;
        try {
            CloudFileDirectory rootDir = share.getRootDirectoryReference();
            //获取对包含该文件的目录的引用
            CloudFileDirectory sampleDir = rootDir.getDirectoryReference(SHARE_FILE_NAME);
            //获取要下载的文件的引用
            CloudFile file = sampleDir.getFileReference(fileName);
            //获取文件复制到新的地址路径  如不需要移动文件至新的路径忽略1和2两句代码即可
//1.            CloudFileDirectory webDir = rootDir.getDirectoryReference(SHARE_NEW_FILE_NAME);
            //复制
//2.            CloudFile copyFile = webDir.getFileReference(newFileName);
            copyFile.startCopy(file);
            System.out.println("文件复制到目标路径:"+file.getUri());//copyFile.getUri()
            flag = true;
        } catch (StorageException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 删除指定文件
     *
     * @param filename 文件名称
     */
    public static void delFile(String filename) {
        try {
            // 获取对共享根目录的引用。
            CloudFileDirectory rootDir = share.getRootDirectoryReference();
            // 获取对要删除的文件所在目录的引用
            CloudFileDirectory containerDir = rootDir.getDirectoryReference(SHARE_FILE_NAME);
            CloudFile file;
            file = containerDir.getFileReference(filename);
            if (file.deleteIfExists()) {
                System.out.println("文件被删除:" + filename);
            } else
                System.err.println("文件不存在:" + filename);
        } catch (StorageException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
}

至此一个简单的demo就完成了,测试过程中如出现以下问题:
1.指定的资源不存在。

com.microsoft.azure.storage.StorageException: The specified resource does not exist.

在copy文件的时候容易出现该问题,如把文件从原地址复制到新地址(不同目录下),直接拼接URI是不起作用的需要使用CloudFileDirectory webDir = rootDir.getDirectoryReference(SHARE_NEW_FILE_NAME); CloudFile copyFile = webDir.getFileReference(newFileName);这种方式重新获取目标地址即可。遇到问题不要慌,记得检查文件路径。

2.错误:指定的资源名称包含无效字符。错误代码:InvalidResourceName

The specifed resource name contains invalid

这个问题就很简单了,由于拼接地址错误导致的。获取目标路径新地址最好使用问题1的解决方式。

扩展资料

Azure Storage 是微软 Azure 云提供的云端存储解决方案,当前支持的存储类型有 Blob、Queue、File 和 Table。

java从azure blob存储下载pdf文件生成sas azure file storage_azure

File Storage 是什么?

Azure File Storage 是一个通过 Server Message Block (SMB) 协议提供云端文件共享的服务。通过 File Storage 共享的文件,能够被加载为云端或本地主机的磁盘,应用程序可以通过文件 API 像访问本地文件一样访问这些文件。

下面是 File Storage 典型的应用场景:

  1. 轻松迁移那些有磁盘读写操作的应用到云端。不用修改程序,只要通过 File Storage 加载相应的文件即可。
  2. 存放共享的应用程序配置文件。
  3. 存放日志等应用程序诊断数据。
  4. 存放管理员的常用工具。

Azure File Storage的结构

下图描述了 File Storage 的基本组织结构:

java从azure blob存储下载pdf文件生成sas azure file storage_spring boot_02

  • Azure Storage Account:
    Storage Account 是用来管理 Azure Storage 的一个命名空间,主要用来控制存储数据的访问权限和计费。对 Blob、Queue、File 和 Table 这些 Azure 提供的存储服务的访问控制,都是通过 Storage Account 来进行的,所以要想使用 File Storage,需要先创建你的 Storage Account。
  • Share:
    Share 是管理共享文件的单位,任何要共享的文件和目录都必须属于某个 Share。一个 Storage Account 下的 Share 数量是不受限制的,每个 Share 中可以存放任何数量的文件。但是每个 Share 中最多能存放5TB 的数据。
  • Directory:
    与 Blob Storage 不同,File Storage 支持真正的文件目录。你可以根据需要来创建目录。
  • File:
    File 是真正被共享的文件,每个文件最大 1TB。
  • URL format:
    与 Blob Storage 相似,File Storage 中的每个文件都可以通过 URL 来访问。