更新时间:2025-03-13 GMT+08:00
分享

C#

分段上传C#语言的示例代码,如下所示:

using System.Net;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml.Linq;
using HuaweiCloud.SDK.Core;
using HuaweiCloud.SDK.Core.Auth;
using HuaweiCloud.SDK.Vod.V1;
using HuaweiCloud.SDK.Vod.V1.Model;


/**
 * 分段上传示例
 */
public class PartUploadDemo
{
    // 设置缓冲区大小,每次读取文件分段的大小,根据情况自行设定
    private const int BuffSize = 1024 * 1024; // 1MB

    // 区域
    private const string RegionNorth4 = "cn-north-4";
    private const string RegionNorth1 = "cn-north-1";
    private const string RegionEast2 = "cn-east-2";

    // ak/sk
    private const string Ak = "";
    private const string Sk = "";

    public static void Start()
    {
        // 本地要上传的媒资路径
        const string filePath = "";

        // 上传媒资文件
        UploadFile(filePath);
    }

    /**
     * 分段上传
     * @param filePath 上传文件的本地路径
     */
    private static void UploadFile(string filePath)
    {
        // 校验一下文件路径和文件
        ValidFile(filePath);

        var fileInfo = new FileInfo(filePath);
        try
        {
            // 此处仅以MP4文件示例,其他格式可以参考官网说明
            var fileType = "MP4";
            var fileContentType = "video/mp4";

            // 1.初始化鉴权并获取vodClient
            var vodClient = CreateVodClient();
            Console.WriteLine("开始创建媒资:" + fileInfo.Name);
            // 2.创建点播媒资
            var assetResponse = CreateAssetByFileUpload(vodClient, fileInfo.Name, fileInfo.Name, fileType);
            // 3.初始化上传任务授权
            var initAuthResponse = InitPartUploadAuthority(vodClient, assetResponse, fileContentType);
            // 4.初始化上传任务
            var uploadId = InitPartUpload(initAuthResponse.SignStr, fileContentType).Result;

            // 文件分段计数
            var partNumber = 1;
            // 记录读取的长度
            var bytesRead = 0;

            // 7. 读取文件内容,循环5-6步上传所有分段
            var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            // 创建一个缓冲区
            var buffer = new byte[BuffSize];
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                // 读取的长度小于缓冲区长度,复制有效长度内数据,用于最后一段
                if (bytesRead != BuffSize)
                {
                    var tmp = new byte[bytesRead];
                    Array.Copy(buffer, tmp, bytesRead);
                    buffer = tmp;
                }

                // 先计算MD5哈希值
                var hashBytes = MD5.HashData(buffer);
                // 再将MD5哈希值转换为Base64字符串
                var contentMd5 = Convert.ToBase64String(hashBytes);
                //输出Base64字符串
                Console.WriteLine("该文件第" + (partNumber) + "段MD5为:" + contentMd5);
                // 5.获取上传分段的授权
                var partUploadAuthorityResponse =
                    GetPartUploadAuthority(vodClient, fileContentType, assetResponse, contentMd5, uploadId, partNumber);
                // 6.上传分段
                var flag = UploadPartFile(partUploadAuthorityResponse.SignStr, buffer, contentMd5).Result;
                // 段号自增
                partNumber++;
            }

            fileStream.Close();
            // 8.获取已上传分段的授权
            var listPartUploadAuthorityResponse = ListUploadedPartAuthority(vodClient, assetResponse, uploadId);
            // 9.获取已上传的分段
            var partInfo = ListUploadedPart(listPartUploadAuthorityResponse.SignStr).Result;
            // 10.获取合并段授权
            var mergePartUploadAuthorityResponse = MergeUploadedPartAuthority(vodClient, assetResponse, uploadId);
            // 11.合并上传分段
            _ = MergeUploadedPart(mergePartUploadAuthorityResponse.SignStr, partInfo).Result;
            // 12.确认媒资上传
            ConfirmUploaded(vodClient, assetResponse);
            Console.WriteLine("创建媒资结束 assetId:" + assetResponse.AssetId);

        }
        catch (RequestTimeoutException requestTimeoutException)
        {
            Console.WriteLine(requestTimeoutException.ErrorMessage);
        }
        catch (ServiceResponseException clientRequestException)
        {
            Console.WriteLine(clientRequestException.HttpStatusCode);
            Console.WriteLine(clientRequestException.RequestId);
            Console.WriteLine(clientRequestException.ErrorCode);
            Console.WriteLine(clientRequestException.ErrorMessage);
        }
        catch (ConnectionException connectionException)
        {
            Console.WriteLine(connectionException.ErrorMessage);
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception.Message);
        }
    }

    /**
     * 校验文件路径和文件
     * @param filePath
     */
    private static void ValidFile(string filePath)
    {
        var fileExists = File.Exists(filePath);
        if (!fileExists)
        {
            // 文件不存在
            throw new Exception("文件不存在");
        }
    }

    /**
     * 1.构建鉴权
     * @return
     */
    private static VodClient CreateVodClient()
    {
        var config = HttpConfig.GetDefaultConfig();
        config.IgnoreSslVerification = true;
        var auth = new BasicCredentials(Ak, Sk);

        var client = VodClient.NewBuilder()
            .WithCredential(auth)
            .WithRegion(VodRegion.ValueOf(RegionNorth4))
            .WithHttpConfig(config)
            .Build();
        return client;
    }

    /**
     * 2.创建媒资
     * @param client
     * @param title
     * @param videoName
     * @param video
     * @return
     */
    private static CreateAssetByFileUploadResponse CreateAssetByFileUpload(VodClient client, string title,
        string videoName,
        string videoType)
    {
        Console.WriteLine("createAssetByFileUpload start");
        var req = new CreateAssetByFileUploadRequest
        {
            Body = new CreateAssetByFileUploadReq()
            {
                Title = title,
                VideoName = videoName,
                VideoType = videoType
            }
        };
        // 调用创建媒资
        var response = client.CreateAssetByFileUpload(req);
        Console.WriteLine("createAssetByFileUpload end; createAssetResponse:" + response);
        return response;
    }

    /**
     * 3.获取初始化上传任务授权
     * @param client
     * @param assetResponse
     * @param fileContentType
     */
    private static ShowAssetTempAuthorityResponse InitPartUploadAuthority(VodClient client,
        CreateAssetByFileUploadResponse assetResponse,
        string fileContentType)
    {
        Console.WriteLine("获取初始化上传任务授权 initPartUploadAuthority start");
        // 设置参数
        var request = new ShowAssetTempAuthorityRequest
        {
            HttpVerb = "POST",
            Bucket = assetResponse.Target.Bucket,
            ObjectKey = assetResponse.Target.Object,
            ContentType = fileContentType
        };
        //发送初始化请求
        var response = client.ShowAssetTempAuthority(request);
        Console.WriteLine("获取初始化上传任务授权 initPartUploadAuthority end; response" + response);
        return response;
    }

    /**
     * 4.初始化分段上传
     * @param signStr
     * @param contentType
     * @return
     */
    private static async Task<string?> InitPartUpload(string signStr, string contentType)
    {
        Console.WriteLine("初始化分段上传 initPartUpload start");
        using var client = new HttpClient();
        var content = new ByteArrayContent([]);
        content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
        var response = await client.PostAsync(signStr, content);
        // 确保请求成功
        response.EnsureSuccessStatusCode();
        var responseBody = await response.Content.ReadAsStringAsync();
        Console.WriteLine(responseBody);
        var root = XElement.Parse(responseBody);
        var ns = root.Name.Namespace;
        var uploadId = root.Element("{" + ns + "}UploadId")?.Value;
        Console.WriteLine("初始化分段上传 initPartUpload end; UploadId:" + uploadId);
        return uploadId;
    }

    /**
     * 5.获取分段上传任务授权
     * @param client
     * @param fileContentType
     * @param assetResponse
     * @param contentMd5
     * @param uploadId
     * @param partNumber
     * @return
     */
    private static ShowAssetTempAuthorityResponse GetPartUploadAuthority(VodClient client,
        string fileContentType, CreateAssetByFileUploadResponse assetResponse, string contentMd5,
        string uploadId, int partNumber)
    {
        // Thread.Sleep(2000);
        Console.WriteLine("获取分段上传任务授权 GetPartUploadAuthority start:" + partNumber);
        // 设置参数
        var request = new ShowAssetTempAuthorityRequest
        {
            HttpVerb = "PUT",
            Bucket = assetResponse.Target.Bucket,
            ObjectKey = assetResponse.Target.Object,
            ContentType = fileContentType,
            // ContentMd5 = contentMd5,
            ContentMd5 = HttpUtility.UrlEncode(contentMd5),
            UploadId = uploadId,
            PartNumber = partNumber
        };
        Console.WriteLine(WebUtility.UrlEncode(contentMd5));
        var response = client.ShowAssetTempAuthority(request);
        Console.WriteLine("获取分段上传任务授权 GetPartUploadAuthority end; response" + partNumber + "; response: " + response + "\n");
        return response;
    }

    /**
     * 6.上传分段
     * @param signStr
     * @param fileByte
     * @param contentMd5
     */
    public static async Task<Boolean> UploadPartFile(string signStr, byte[] fileByte, string contentMd5)
    {
        Console.WriteLine("上传分段 uploadPartFile start");
        HttpClient client = new HttpClient();
        HttpContent content = new ByteArrayContent(fileByte);
        content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        content.Headers.Add("Content-MD5", contentMd5);
        HttpResponseMessage response = await client.PutAsync(signStr, content);
        Console.WriteLine("上传分段 response:" + response);
        response.EnsureSuccessStatusCode(); // 确保请求成功
        var responseBody = await response.Content.ReadAsStringAsync();
        Console.WriteLine("上传分段 uploadPartFile end; response:" + responseBody);
        return true;
    }

    /**
     * 8.获取列举上传分段的授权
     * @param client
     * @param assetResponse
     * @param uploadId
     * @return
     */
    private static ShowAssetTempAuthorityResponse ListUploadedPartAuthority(VodClient client,
        CreateAssetByFileUploadResponse assetResponse, string? uploadId)
    {
        Console.WriteLine("获取列举已上传段的授权 listUploadedPartAuthority start");
        var request = new ShowAssetTempAuthorityRequest
        {
            HttpVerb = "GET",
            Bucket = assetResponse.Target.Bucket,
            ObjectKey = assetResponse.Target.Object,
            UploadId = uploadId
        };
        var response = client.ShowAssetTempAuthority(request);
        Console.WriteLine("获取列举已上传段的授权 listUploadedPartAuthority end; response: " + response);
        return response;
    }

    /**
     * 9.查询已上传的分段
     * @param signStr
     * @return
     */
    private static async Task<string> ListUploadedPart(string signStr)
    {
        Console.WriteLine("查询已上传的分段 listUploadedPart start");
        var partNumberMarker = 0;
        var mergerRoot = new XElement("CompleteMultipartUpload");
        while (true)
        {
            // 列举分段
            using var client = new HttpClient();
            var response = await client.GetAsync(signStr + "&part-number-marker=" + partNumberMarker);
            response.EnsureSuccessStatusCode();
            var responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseBody);
            var root = XElement.Parse(responseBody);
            var ns = root.Name.Namespace;
            var partNodes = root.Elements("{" + ns + "}Part");
            var partNumberMarkerElement = root.Element("{" + ns + "}NextPartNumberMarker");
            foreach (var partNode in partNodes)
            {
                var partNumberNode = partNode.Element("{" + ns + "}PartNumber");
                var partNumber = partNumberNode?.Value;
                var eTagNode = partNode.Element("{" + ns + "}ETag");
                var etag = eTagNode?.Value;
                var part = new XElement("Part");
                mergerRoot.Add(part);
                part.Add(new XElement("PartNumber", partNumber));
                part.Add(new XElement("ETag", etag));
            }
            partNumberMarker = Convert.ToInt32(partNumberMarkerElement?.Value);
            if (partNumberMarker == 0 || partNumberMarker % 1000 != 0)
            {
                break;
            }
        }
        Console.WriteLine(mergerRoot.ToString());
        Console.WriteLine("查询已上传的分段 listUploadedPart end");
        return mergerRoot.ToString();
    }

    /**
     * 10.获取合并段授权
     * @param client
     * @param assetResponse
     * @param uploadId
     * @return
     */
    private static ShowAssetTempAuthorityResponse MergeUploadedPartAuthority(VodClient client,
        CreateAssetByFileUploadResponse assetResponse, string? uploadId)
    {
        Console.WriteLine("获取合并段授权 mergeUploadedPartAuthority start");
        var request = new ShowAssetTempAuthorityRequest
        {
            HttpVerb = "POST",
            Bucket = assetResponse.Target.Bucket,
            ObjectKey = assetResponse.Target.Object,
            UploadId = uploadId
        };
        var response = client.ShowAssetTempAuthority(request);
        Console.WriteLine("获取合并段授权 mergeUploadedPartAuthority end; response: " + response);
        return response;
    }

    /**
     * 11.合并分段
     */
    public static async Task<Boolean> MergeUploadedPart(string signStr, string partInfo)
    {
        Console.WriteLine("合并分段 mergeUploadedPart start");
        using var client = new HttpClient();
        // 请求消息头中增加"content-Type", 值设置为"application/xml"
        HttpContent content = new StringContent(partInfo);
        content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
        var response = await client.PostAsync(signStr, content);
        var responseBody = await response.Content.ReadAsStringAsync();
        Console.WriteLine(responseBody);
        response.EnsureSuccessStatusCode();
        Console.WriteLine("合并分段 mergeUploadedPart end");
        return true;
    }

    /**
     * 确认上传完成
     */
    private static void ConfirmUploaded(VodClient client, CreateAssetByFileUploadResponse assetResponse)
    {
        Console.WriteLine("确认上传完成 confirmUploaded start");
        var request = new ConfirmAssetUploadRequest
        {
            Body = new ConfirmAssetUploadReq()
            {
                Status = ConfirmAssetUploadReq.StatusEnum.FromValue("CREATED"),
                AssetId = assetResponse.AssetId
            }
        };
        var response = client.ConfirmAssetUpload(request);
        Console.WriteLine("上传完成, assetId: " + response);
    }
}

相关文档