【Azure 存储服务】.NET7.0 示例代码之上传大文件到Azure Storage Blob (二)

问题描述

在上一篇博文(【Azure 存储服务】.NET7.0 示例代码之上传大文件到Azure Storage Blob (一):http://www.cnblogs.com/lulight/p/17061631.html)中,介绍了第一种分片的方式上传文件。 本文章接着介绍第二种方式,使用 Microsoft.Azure.Storage.DataMovement 库中的 TransferManager.UploadAsync 通过并发的方式来上传大文件。

问题回答

第一步:添加 Microsoft.Azure.Storage.DataMovement  

dotnet add package Microsoft.Azure.Storage.DataMovement

第二步:编写示例代码

        String storageConnectionString = "xxxxxxxxxxxxxxxxxxx";

        CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
        CloudBlobClient blobclient = account.CreateCloudBlobClient();
        CloudBlobContainer blobcontainer = blobclient.GetContainerReference("uploadfiles-123");
        await blobcontainer.CreateIfNotExistsAsync();

        // 获取文件路径
        string sourcePath = @"C:\home\bigfiles0120.zip";
        CloudBlockBlob docBlob = blobcontainer.GetBlockBlobReference("bigfiles-2");
        await docBlob.DeleteIfExistsAsync();

        // 设置并发操作的数量
        TransferManager.Configurations.ParallelOperations = 64;
        // 设置单块 blob 的大小,它必须在 4MB 到 100MB 之间,并且是 4MB 的倍数,默认情况下是 4MB
        TransferManager.Configurations.BlockSize = 64 * 1024 * 1024;
        // 设置传输上下文并跟踪上传进度
        var context = new SingleTransferContext();
        UploadOptions uploadOptions = new UploadOptions
        {
            DestinationAccessCondition = AccessCondition.GenerateIfExistsCondition()
        };
        context.ProgressHandler = new Progress<TransferStatus>(progress =>
        {
            //显示上传进度
            Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred);
        });
        // 使用 Stopwatch 查看上传所需时间
        var timer = System.Diagnostics.Stopwatch.StartNew();
        // 上传 Blob
        TransferManager.UploadAsync(sourcePath, docBlob, uploadOptions, context, CancellationToken.None).Wait();
        timer.Stop();
        Console.WriteLine("Time (millisecond):" + timer.ElapsedMilliseconds);
        Console.WriteLine("upload success");

第一种分片方式上传和第二步并发上传的代码执行对比:

 

全部代码

Program.cs

// See http://aka.ms/new-console-template for more information

Console.WriteLine("Hello, World! Start to upload big files...");

//第一种上传文件方法: Microsoft.WindowsAzure.Storage
Console.WriteLine("第一种上传文件方法: Microsoft.WindowsAzure.Storage");
await UploadMethodOne.WindowsAzureStorageUpload();

//第二种上传文件方法: Microsoft.Azure.Storage.DataMovement
Console.WriteLine("第二种上传文件方法: Microsoft.Azure.Storage.DataMovement");
await UploadMethodTwo.DataMovementUploadFiletoBlob();

Console.WriteLine("End!");

UploadMethodOne.cs

using Microsoft.Azure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.RetryPolicies;

public static class UploadMethodOne
{
    public static async Task WindowsAzureStorageUpload()
    {
        TimeSpan backOffPeriod = TimeSpan.FromSeconds(2);
        int retryCount = 1;
        //设置请求选项
        BlobRequestOptions requestoptions = new BlobRequestOptions()
        {
            SingleBlobUploadThresholdInBytes = 1024 * 1024 * 10, //10MB
            ParallelOperationThreadCount = 12,
            RetryPolicy = new ExponentialRetry(backOffPeriod, retryCount),
        };

        //String storageConnectionString = System.Environment.GetEnvironmentVariable("StorageConnectionString", EnvironmentVariableTarget.User);
        //Console.WriteLine("String account string : "+storageConnectionString);
        String storageConnectionString = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
        CloudBlobClient blobclient = account.CreateCloudBlobClient();
        //设置客户端默认请求选项
        blobclient.DefaultRequestOptions = requestoptions;
        CloudBlobContainer blobcontainer = blobclient.GetContainerReference("uploadfiles-123");


        await blobcontainer.CreateIfNotExistsAsync();
        //文件路径,文件大小 
        string sourcePath = @"C:\home\bigfiles0120.zip";
        CloudBlockBlob blockblob = blobcontainer.GetBlockBlobReference("bigfiles-1");
        //设置单个块 Blob 的大小(分块方式)
        blockblob.StreamWriteSizeInBytes = 1024 * 1024 * 5;
        try
        {
            Console.WriteLine("uploading");
            //使用 Stopwatch 查看上传时间
            var timer = System.Diagnostics.Stopwatch.StartNew();
            using (var filestream = System.IO.File.OpenRead(sourcePath))
            {
                await blockblob.UploadFromStreamAsync(filestream);
            }
            timer.Stop();

            Console.WriteLine(timer.ElapsedMilliseconds);

            Console.WriteLine("Upload Successful, Time:" + timer.ElapsedMilliseconds);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }

    }
}

 

UploadMethodTwo.cs

using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
using Microsoft.Azure.Storage.DataMovement;
public static class UploadMethodTwo
{
    public async static Task DataMovementUploadFiletoBlob()
    {
        String storageConnectionString = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

        CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString);
        CloudBlobClient blobclient = account.CreateCloudBlobClient();
        CloudBlobContainer blobcontainer = blobclient.GetContainerReference("uploadfiles-123");
        await blobcontainer.CreateIfNotExistsAsync();

        // 获取文件路径
        string sourcePath = @"C:\home\bigfiles0120.zip";
        CloudBlockBlob docBlob = blobcontainer.GetBlockBlobReference("bigfiles-2");
        await docBlob.DeleteIfExistsAsync();

        // 设置并发操作的数量
        TransferManager.Configurations.ParallelOperations = 64;
        // 设置单块 blob 的大小,它必须在 4MB 到 100MB 之间,并且是 4MB 的倍数,默认情况下是 4MB
        TransferManager.Configurations.BlockSize = 64 * 1024 * 1024;
        // 设置传输上下文并跟踪上传进度
        var context = new SingleTransferContext();
        UploadOptions uploadOptions = new UploadOptions
        {
            DestinationAccessCondition = AccessCondition.GenerateIfExistsCondition()
        };
        context.ProgressHandler = new Progress<TransferStatus>(progress =>
        {
            //显示上传进度
            Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred);
        });
        // 使用 Stopwatch 查看上传所需时间
        var timer = System.Diagnostics.Stopwatch.StartNew();
        // 上传 Blob
        TransferManager.UploadAsync(sourcePath, docBlob, uploadOptions, context, CancellationToken.None).Wait();
        timer.Stop();
        Console.WriteLine("Time (millisecond):" + timer.ElapsedMilliseconds);
        Console.WriteLine("upload success");
    }
}

 

参考资料

上传大文件到 Azure 存储块 Blob:http://docs.azure.cn/zh-cn/articles/azure-operations-guide/storage/aog-storage-blob-howto-upload-big-file-to-storage

 

当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!

本文转载于网络 如有侵权请联系删除

相关文章

  • 数字货运角逐:满帮化零为整,福佑化整为零

    配图来自Cnava可画尽管今天中国的货运业已经具备相当的规模,来自淘宝京东的包裹更是川流不息,但物流仍旧是各个企业发展过程中的“不可忽视”之痛——太贵了。从数据来看,2020年中国物流成本占GDP比重约为14.7%,几乎是美国该数值(7.6%)的两倍。而且国内物流有接近1/3的支出,是因为信息不对称导致的,按照中国GDP总体数值,这种浪费每降低一个百分点就能每年节省数百亿。造成信息不对称,或者说造成信息在匹配过程中出现“噪音”的,却恰恰就是货运行业的参与者自己。但这不能简单地将责任归结在它们身上:客观来看,截至2020年底,中国有大约810万家承运人,平均每家有4辆卡车,而美国这两个数字分别为60万家和26辆。由于承运人太过分散,造成从业者过多,货运行业实际上也体现出畸形和病态发展。在这种情况下,数字化的货运平台作为“终极解决方案”应运而生。但作为新生事物,一方面,货运平台能够参与其中的范围有限,不同领域的物流生态截然不同,贸然进场反而可能坏事;另一方面,货运平台就发展程度而言,还处于较为早期的阶段,潜力还未全部发挥出来。解决货运难题迫在眉睫根据麦肯锡数据,广义的道路运输可以大致分为快

  • Python协程与异步编程超全总结

    前言 异步IO:就是发起一个IO操作(如:网络请求,文件读写等),这些操作一般是比较耗时的,不用等待它结束,可以继续做其他事情,结束时会发来通知。 协程:又称为微线程,在一个线程中执行,执行函数时可以随时中断,由程序(用户)自身控制,执行效率极高,与多线程比较,没有切换线程的开销和多线程锁机制。Python中异步IO操作是通过asyncio来实现的。异步IO 异步IO的asyncio库使用事件循环驱动的协程实现并发。用户可主动控制程序,在认为耗时IO处添加await(yieldfrom)。在asyncio库中,协程使用@asyncio.coroutine装饰,使用yieldfrom来驱动,在python3.5中作了如下更改:@asyncio.coroutine->asyncyieldfrom->awaitPython3.8之后@asyncio.coroutine装饰器就会被移除,推荐使用async&await关键字实现协程代码。asyncio异步中几个重要概念1.事件循环管理所有的事件,在整个程序运行过程中不断循环执行并追踪事件发生的顺序将它们放在队列中,空闲时调

  • 聊聊debezium的SimpleSourceConnector

    序本文主要研究一下debezium的SimpleSourceConnectorSimpleSourceConnectordebezium-v1.1.1.Final/debezium-embedded/src/main/java/io/debezium/connector/simple/SimpleSourceConnector.javapublicclassSimpleSourceConnectorextendsSourceConnector{ protectedstaticfinalStringVERSION="1.0"; publicstaticfinalStringTOPIC_NAME="topic.name"; publicstaticfinalStringRECORD_COUNT_PER_BATCH="record.count.per.batch"; publicstaticfinalStringBATCH_COUNT="batch.count"; publicstaticfinalStrin

  • 【算法】归并排序及其应用

    一、归并排序归并排序的思路归并排序是典型的分治算法,把一个数组的排序,分为两个子序列的排序,然后将两个有序序列合并。以上就是整个算法的核心。整个过程如下图所示(图侵删):归并排序图解具体实现如下:publicstaticvoidmerge(int[]arr){ if(arr==null||arr.length<2){ return; } mergeSort(arr,0,arr.length-1); } publicstaticvoidmergeSort(int[]arr,intl,intr){ if(l==r){ return; } //intmid=(l+r)/2; //等同于以上写法,这样的好处是防止溢出 intmid=l+((r-l)>>1); mergeSort(arr,l,mid); mergeSort(arr,mid+1,r); merge(arr,l,mid,r); } ///合并两个有序数组为新的有序数组 publicstaticvoidmerge(int[]arr,intl,intm,intr){ int[]help=newint[r-l+1];

  • Python -- 异常处理

    【简介异常】  异常是什么 异常是一个事件,该事件在执行过程中发生,影响了程序正常执行。异常是python对象,表示一个错误。而我们要做的事发生异常后捕获并处理它,否则程序会终止。try:  <语句>        #运行别的代码  except <name>:  <语句>        #如果在try部份引发了'name'异常  except <name>,<数据>:  <语句>        #如果引发了'name'异常,获得附加的数据  else:  <语句>        #如果没有异常发生复制工作原理  当try开始后,python在当前程序的上下文做标记,当异常出现时就回到这里,try子句先执行,接下来发生的事依赖于出现什么异常。1、try子语句执行后发生异常,python去逐个匹配except子句,匹配并处理完毕,控制流就通过了整个try语句(除非期间又发生了新的异常)2、try子语句发生异常后,没有匹配到except子句,异常呗递交到上层try,或

  • 对象原理探究(一)

    一、定位源码位置我们要探究一个对象,那么就要找到其属性或者方法等所对应的源码。首先,我来介绍三种探索源码(即定位源码位置)的方式。 示例代码:LaVieLeader*leader1=[LaVieLeaderalloc];LaVieLeader*leader2=[leader1init];LaVieLeader*leader3=[leader1init];NSLog(@"%@,%@,%@",leader1,leader2,leader3);NSLog(@"%p,%p,%p",&leader1,&leader2,&leader3);复制其打印结果: 2019-12-1508:58:07.799176+0800msg_send[1184:250725]<LaVieLeader:0x281e403b0>,<LaVieLeader:0x281e403b0>,<LaVieLeader:0x281e403b0>2019-12-1508:58:07.799305+0800msg_send[1184:25

  • 白话虚拟dom

    又到了发文章的时候了,今天和大家一起来讨论下虚拟dom,为什么要讨论这个玩意呢,因为现在最流行的两个前端框架都用到了虚拟dom。首先咱们从起源说起,做web开发的时候,当数据发生变化的时候,我们要去更新dom,从而给前端用户呈现最新的数据,流程图如下:数据更改后直接操作dom,我们举例来看一下需求,比方说一个列表,列表下面有一个点击加载更多的按钮:点击加载更多,会发送一个ajax请求,请求更多的数据,然后将数据渲染到页面,我们一般会如何做呢,代码片段如下:我们看到,每次数据更新后,我们借助模板生成html片段,获取列表的新旧内容拼接,这里我们思考一下,就会发现已经存在的列表信息是不应该重新渲染的。上面的案例先放一边,先了解一下什么是虚拟dom,简单来说就是一句话,用js对象来描述dom结构,示例如下:有如下dom结构:<ulid='list'> <liclass='item'>item1</li> <liclass='item'>item2</li> </ul&

  • ccf 高速公路(连通子图)

    问题描述  某国有n个城市,为了使得城市间的交通更便利,该国国王打算在城市之间修一些高速公路,由于经费限制,国王打算第一阶段先在部分城市之间修一些单向的高速公路。   现在,大臣们帮国王拟了一个修高速公路的计划。看了计划后,国王发现,有些城市之间可以通过高速公路直接(不经过其他城市)或间接(经过一个或多个其他城市)到达,而有的却不能。如果城市A可以通过高速公路到达城市B,而且城市B也可以通过高速公路到达城市A,则这两个城市被称为便利城市对。   国王想知道,在大臣们给他的计划中,有多少个便利城市对。输入格式  输入的第一行包含两个整数n,m,分别表示城市和单向高速公路的数量。   接下来m行,每行两个整数a,b,表示城市a有一条单向的高速公路连向城市b。输出格式  输出一行,包含一个整数,表示便利城市对的数量。样例输入55 12 23 34 42 35样例输出3样例说明   城市间的连接如图所示。有3个便利城市对,它们分别是(2,3),(2,4),(3,4),请注意(2,3)和(3,2)看成同一个便利城市对。评测用例规模与约定  前30%的评测用例满足1≤n≤100,1≤m≤1000;

  • IDEA快捷键拆解系列(十三):Window篇

      这是IDEA快捷键拆解系列的第十三篇。  以下是关于Window导航项及其每一子项的拆解介绍,其中,加粗部分的选项是博主认为比较重要的。WindowQuickRunRootMavenGoalCtrl+Shift+Alt+RQuickRunMavenGoalCtrl+Alt+RStoreCurrentLayoutasDefault(存储当前为默认布局)RestoreDefaultLayout(还原默认布局)Shift+F12ActiveToolWindow(ToolWindows相关)HideActiveToolWindow(隐藏激活工具窗)Shift+EscHideSideToolWindowsRestoreWindows(还原窗口)Ctrl+Shift+F12CloseActiveTab(关闭激活的Tab)Ctrl+Shift+F4JumptoLastToolWindow(定位到上一个操作工具窗)F12MaximizeToolWindow(最大化工具窗口)Ctrl+Shift+引号Pinnedmode(勾选上为固定模式的窗口(默认),不勾选上当离开当前窗口时会隐藏)Dockedm

  • 利用Python实现卷积神经网络的可视化

    源|全球人工智能文|小象摘要:本文简单说明了CNN模型可视化的重要性,以及介绍了一些可视化CNN网络模型的方法,希望对读者有所帮助,使其能够在后续深度学习应用中构建更好的模型。对于深度学习这种端到端模型来说,如何说明和理解其中的训练过程是大多数研究者关注热点之一,这个问题对于那种高风险行业显得尤为重视,比如医疗、军事等。在深度学习中,这个问题被称作“黑匣子(BlackBox)”。如果不能解释模型的工作过程,我们怎么能够就轻易相信模型的输出结果呢?以深度学习模型检测癌症肿瘤为例,该模型告诉你它能够检测出癌症的准确率高达99%,但它并没有告诉你它是如何工作并给出判断结果的。那么该模型是在核磁共振扫描片子中发现了重要线索吗?或者仅仅是将扫描结果上的污点错误地认为是肿瘤呢?模型的输出结果关系到病人的生死问题及治疗方案,医生是不能承担起这种错误的。在本文中,将探讨如何可视化卷积神经网络(CNN),该网络在计算机视觉中使用最为广泛。首先了解CNN模型可视化的重要性,其次介绍可视化的几种方法,同时以一个用例帮助读者更好地理解模型可视化这一概念。1.卷积神经网络模型可视化的重要性正如上文中介绍的癌症肿

  • 临床预测模型之二分类资料ROC曲线绘制

    ROC曲线是评价模型的重要工具,曲线下面积AUC可能是大家最常见的模型评价指标之一。如果你还不太了解关于ROC曲线中的各种指标,请看下面这张图,有你需要的一切(建议保存):混淆矩阵混淆矩阵计算R语言中有非常多的方法可以实现ROC曲线,但是基本上都是至少需要2列数据,一列是真实结果,另一列是预测值,有了这两列数据,就可以轻松使用各种方法画出ROC曲线并计算AUC。这篇文章带大家介绍最常见的并且好用的二分类变量的ROC曲线画法。方法1方法2方法3方法1使用pROC包,不过使用这个包需要注意,一定要指定direction,否则可能会得出错误的结果。这个R包计算AUC是基于中位数的,哪一组的中位数大就计算哪一组的AUC,在计算时千万要注意!使用pROC包的aSAH数据,其中outcome列是结果变量,1代表Good,2代表Poor。library(pROC) ##Type'citation("pROC")'foracitation. ## ##载入程辑包:'pROC' ##Thefollowingobjectsaremaskedfro

  • web.xml配置详解

    1定义头和根元素   部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。  DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本(如2.2或2.3)并指定管理此文件其余部分内容的语法的DTD(DocumentTypeDefinition,文档类型定义)。  所有部署描述符文件的顶层(根)元素为web-app。请注意,XML元素不像HTML,他们是大小写敏感的。因此,web-App和WEB-APP都是不合法的,web-app必须用小写。  2部署描述符文件内的元素次序   XML元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感。例如,XML头必须是文件中的第一项,DOCTYPE声明必须是第二项,而web-app元素必须是第三项。在web-app元素内,元素的次序也很重要。服务器不一定强制要求这种次序,但它们允许(实际上有些服务器就是这样做的)完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。  下面的列表给出了

  • celery worker集群搭建

    举个小栗子,在生产环境下,我们有两个异步任务需求,需要分别部署在两台服务器上,并用不同的队列实现 用户邮件发送 pageview统计 主要的注意点,在任务执行时需指定queue,routing_key 文件结构 celery_demo#项目根目录 ├──celery_app#存放celery相关文件 │├──__init__.py │├──celeryconfig.py#配置文件 │├──task1.py#任务文件1 │└──task2.py#任务文件2 └──client.py#应用程序 复制 init.py fromceleryimportCelery app=Celery('demo')#创建Celery实例 app.config_from_object('celery_app.celeryconfig')#通过Celery实例加载配置模块 __all__=['app'] 复制 celeryconfig.py fromkombuimportQueue fromkombuimportExchange BROKER_URL='redis://192.168.31.45

  • Windows Phone 应用程序的生命周期(二)

    一.App.xaml.cs ///<summary> ///Application对象的构造函数。 ///</summary> publicApp() { //未捕获的异常的全局处理程序。 UnhandledException+=Application_UnhandledException; //标准XAML初始化 InitializeComponent(); //特定于电话的初始化 InitializePhoneApplication(); //语言显示初始化 InitializeLanguage(); //调试时显示图形分析信息。 if(Debugger.IsAttached) { //显示当前帧速率计数器。 Application.Current.Host.Settings.EnableFrameRateCounter=true; //显示在每个帧中重绘的应用程序区域。 //Application.Current.Host.Settings.EnableRedrawRegions=true; //启用非生产分析可视化模式, //该模式显示递交

  • datatables 自定义排序

    参考:https://datatables.net/examples/plug-ins/sorting_manual $.fn.dataTable.ext.type.order['salary-grade-pre']= function (d){     switch (d){         case 'Low':    return 1;         case 'Medium': return 2;         case 'High':   return 3;     }  &nbs

  • ccf-csp201909题解

    ccf-csp201909题解 标签:ccf题解 目录ccf-csp201909题解1.201909-1 小明种苹果题目描述解析通过代码2.201909-2 小明种苹果(续)题目描述解析通过代码3.201909-3字符画题目描述解析a代表像素块颜色为(aa,aa,aa)abc代表像素块颜色为(aa,bb,cc)abcdef代表像素块颜色为(ab,cd,ef)通过代码4.201909-4推荐系统题目描述解析通过代码 1.201909-1 小明种苹果 题目描述 试题编号: 201909-1 试题名称: 小明种苹果 时间限制: 2.0s 内存限制: 512.0MB 解析 简单模拟题。 题中要求三个值,苹果的总数T,疏果最大值所在树的序号k,疏果最大值P。 维护T只要将输入从第二行开始所有数都相加即可,维护k和P只需维护输入每行第二个数开始加和的最小值即可。 通过代码 //1592771 <13100928923> <王恪楠> 小明种苹果 11-0520:11 603B C0X 正确 100 796ms 540.0KB #include<bits/s

  • 使用haproxy负载均衡

    测试中

  • Swift自定义AlertView

    今天项目加新需求,添加积分过期提醒功能: 第一反应就用系统的UIAlertViewController,但是message中积分是需要红色显示。 //letstr="尊敬的顾客,您有1000积分即将过期,请尽快使用" //letattributeStr=changeTextChange(regex:"\\d+",text:str,color:UIColor.red) //letalertController=UIAlertController(title:"积分即将过期提醒", //message:attributeStr.string,preferredStyle:.alert) //letcancelAction=UIAlertAction(title:"兑换菜品",style:.cancel,handler:nil) //letokAction=UIAlertAction(title:"暂不兑换",style:.default,handler:{ //actionin //print("点击了确定") //}) //alertController.addAction(canc

  • BZOJ1787_紧急集合_KEY

    题目传送门 LCA,对于每一个(x,y,z),两两求LCA得最优解或求出LCA不同于其他两组的那个为最优解。 code: /**************************************************************     Problem:1787     User:yekehe     Language:C++     Result:Accepted     Time:5212ms     Memory:51604kb ****************************************************************/   #include<cstdio> #include<cstring> #include<algorithm> usi

  • VI

    VIM功能强大,一旦掌握了,威力无穷阿!                扩展模式:       打开两个文件查看或比较:   

  • 组队项目

     此次组队完成“爱吖”音乐播放器这个项目,在团队中我负责的主要任务是收集,整理,修订,完善项目需求文档。需求文档的主要内容如下: 1.项目准备 1.1项目的目的和范围 1.1.1项目开发背景  影音播放是智能手机的中的重要组成部分。事实上,无论是iOS还是android中的原生影音播放器都不太智能。这些系统自带的播放器,基本上只具备基础的播放功能,根本满足不了用户对影音播放的需求。因此,智能影音播放软件应运而生。 一款专业的音乐播放软件是移动智能设备中必不可少的要素,几乎市场上所有的移动智能设备都拥有一个自带的音乐软件。虽然这些音乐软件可以对音乐欣赏中一些必要的元素进行人性化的设置,而且我们在操作的时候也能得到一定的便利,但是不能满足用户的所有要求。所以开发一款个性化的音乐软件是非常有必要的。 1.1.2项目简介 当前市面上的QQ音乐,酷狗音乐,酷我音乐,百度音乐,网易云音乐等音乐播放器的功能已经做得相当全面,并且都有强大的服务作为支撑,我们要想再做出一款受人喜爱的音乐播放器肯定不能拘泥于简单的音乐播放和下载功能上。 结合当前大学生以及庞大的青年群体的现状,各种微社

相关推荐

推荐阅读