阿里云视频点播文件上传-iOS

2023-10-31

阿里云视频点播文件上传-iOS

写在前面:

阿里云-上传SDK文档
阿里云-Api常见错误码表

使用前需先开通视频点播权限,见文档,否则Api访问无效,上传不上去的。

如果只是单纯的上传文件,而不是点播文件,使用简单上传就可以了,视频点播上传是针对点播服务的。刚开始不太清楚,搞了半天视频点播上传,发现Api访问无权限,后来才看到需要开通服务。

一、上传方式

1、上传地址加凭证

2、STS方式上传

方式一 上传地址加凭证上传

这是阿里官方推荐使用的上传方式

与STS方式流程基本一致,只有4点不同的地方

1、请求AppServer

请求AppServer的时候需要让server返回uploadAddress(上传地址)和uploadAuth(上传凭证)

2、在start的回调中设置上传地址和上传凭证

	OnUploadStartedListener UploadStartedCallbackFunc = ^(UploadFileInfo* fileInfo) {
		NSLog(@"upload upload started callback.");
		// 设置上传地址 和 上传凭证
		[weakSelf.uploader setUploadAuthAndAddress:fileInfo uploadAuth:`upload auth` uploadAddress:`upload address`];
	};	

3、uploadAuth过期重新设置

	OnUploadTokenExpiredListener TokenExpiredCallbackFunc = ^{
		NSLog(@"upload token expired callback.");
		// token过期,设置新的上传凭证,继续上传
		[weakSelf.uploader resumeWithAuth:`new upload auth`];
	};

4、上传图片和上传视频

STS上传视频和地址,请求AppServer返回都是key,secreatKey,token和过期时间,就可以上传视频和图片资源。

上传地址+凭证的上传方式注意:

  • 客户端上传视频:需要请求向AppServer发送请求,AppServer通过OpenApi向阿里云点播服务发送CreateUploadVideo请求。请求成功将返回上传地址,上传凭证以及VideoId,AppServer需要将结果返回给客户端。

  • 客户端上传图片:需要请求向AppServer发送请求,AppServer通过OpenApi向阿里云点播服务发送CreateUploadImage请求。请求成功将返回上传地址,上传凭证以及ImageURL,AppServer需要将结果返回给客户端。

方式二 STS方式上传

不推荐使用,可能会被废弃

1、请求STS

向自己的AppServer请求相关的AccessKeyId、AccessKeySecret、SecurityToken等信息。

2、初始化上传对象

初始化VODUploadClient对象,并调用以下方法设置STS授权信息

- (BOOL)        init:(NSString *)accessKeyId
     accessKeySecret:(NSString *)accessKeySecret
         secretToken:(NSString *)secretToken
          expireTime:(NSString *)expireTime
            listener:(VODUploadListener *) listener

STS方式调用init: accessKeySecret: secretToken: expireTime: listener:方法初始化,初始化参数即是第一步请求获取的临时STS凭证。

想不明白起名为什么要起init…,最新版的SDK里Api有所改动,这个方法改成了setAccessKeyId…。

3、回调设置

在初始化uploader对象的时候,顺便设置事件回调。

4、添加上传文件进入上传列表,支持视频文件和图片文件的上传

- (BOOL)addFile:(NSString *)filePath
        vodInfo:(VodInfo *)vodInfo;

5、启动上传

- (BOOL)start;

6、回调处理

略…

二、注意事项

  • 1.5.3版本的readme里面,推荐使用上传凭证的方式上传

  • STS上传方式可能会被废弃

  • 使用VODUpload.framework的话需要后台开通视频点播服务权限,否则接口访问受限

三、错误和异常处理

1、Undefined symbols for architecture x86_64

未添加依赖库,看Demo里有添加libresolv.tbd,libresolv.9.tbd、SystermConfigration.framework。

2、[VODUploadClient initMultiUpload]_block_invoke

初始化问题,未调用init方法设置STS授权信息。

3、failed code = (null), error message = (null)

报错如下

2019-10-21 11:09:02.791887+0800 UploadDemo[5606:1449184] upload started . 2019-10-21 11:09:02.802116+0800 UploadDemo[5606:1449184] failed code = (null), error message = (null) 2019-10-21 11:09:02.802214+0800 UploadDemo[5606:1449184] state 5

不知道怎么处理,更新最新的SDK吧,旧的SDK是有这个问题。

4、Undefined symbols:_CMTimeGetSeconds

报错如下

Undefined symbols for architecture arm64: "_CMTimeRangeGetEnd", referenced from: +[AVCVAssetInfo AVCVVideoDuration:] in VODUpload(AVCVAssetInfo.o) +[AVCVAssetInfo AVCVAudioDuration:] in VODUpload(AVCVAssetInfo.o) "_CMTimeGetSeconds", referenced from: +[AVCVAssetInfo AVCVDuration:] in VODUpload(AVCVAssetInfo.o) +[AVCVAssetInfo AVCVVideoDuration:] in VODUpload(AVCVAssetInfo.o) +[AVCVAssetInfo AVCVAudioDuration:] in VODUpload(AVCVAssetInfo.o) "_AVMediaTypeAudio", referenced from: +[AVCVAssetInfo AVCVAudioDuration:] in VODUpload(AVCVAssetInfo.o) "_AVMediaTypeVideo", referenced from: +[AVCVAssetInfo AVCVNaturalSize:] in VODUpload(AVCVAssetInfo.o) +[AVCVAssetInfo AVCVFrameRate:] in VODUpload(AVCVAssetInfo.o) +[AVCVAssetInfo AVCVBitrate:] in VODUpload(AVCVAssetInfo.o) +[AVCVAssetInfo AVCVVideoDuration:] in VODUpload(AVCVAssetInfo.o) "_OBJC_CLASS_$_AVURLAsset", referenced from: objc-class-ref in VODUpload(VODUploadClient.o) ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation)
官网上说要添加-Objc,force load,统统删掉,编译,OK了。

但是一初始化上传对象,编译,又报错了,什么情况呢?后来联系了阿里的技术服务和技术的童鞋。

原来是缺少了依赖库,也不用设置force load,-Objc什么的,需要添加的依赖库有:

libresolve.tbd
libresolve.9.tbd
SystermCongiguration.framework
MobileCoreService.framework
CoreMedia.ramework
AVFoundation.framework

这些官方文档上可是没有说的,就是对着Demo添加也添加不全的。

5、Forbidden.RAM

上传报错

failed code = Forbidden.RAM, error message = You are not authorized to operate this resource, or this API does not support RAM.

报这个错误,是没有权限使用上传Api,我是因为后台没有开通点播服务导致的。

四、实现代码

这个代码不是很合理,看看就行了。

STS上传方式源码

STS已经不被推荐使用了,这里直接跳过吧。

#import "VHVideoUploder.h"
#import <VODUpload/VODUploadClient.h>
#import "VHVideoUploadModel.h"
#import "VHWebService.h"

@interface VHVideoUploder ()

@property (nonatomic, strong) VODUploadClient *uploader;
@property (nonatomic, strong) VODUploadListener *listener;

@property (nonatomic, copy) NSString *userAccessToken;

@end

@implementation VHVideoUploder

/**
 获取SDK版本号
 */
+ (NSString *)getSDKVersion {
    return SDK_Version;
}

#pragma mark - init

- (VODUploadClient *)uploader {
    if (!_uploader) {
        _uploader = [[VODUploadClient alloc] init];
        
        __weak typeof(self)weakSelf = self;
        
        OnUploadFinishedListener finishedCallbackFunc = ^(UploadFileInfo* fileInfo, VodUploadResult* result) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"%@", [NSString stringWithFormat:@"upload success! %@", fileInfo.filePath]);
                
            });
        };
        
        OnUploadFailedListener testFailedCallbackFunc = ^(UploadFileInfo* fileInfo, NSString *code, NSString* message){
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"failed code = %@, error message = %@", code, message);
                NSLog(@"state %ld",(long)fileInfo.state);
            });
        };
        
        OnUploadProgressListener testProgressCallbackFunc = ^(UploadFileInfo* fileInfo, long uploadedSize, long totalSize) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"progress uploadedSize : %li, totalSize : %li", uploadedSize, totalSize);
                
            });
        };
        
        OnUploadTokenExpiredListener testTokenExpiredCallbackFunc = ^{
            NSLog(@"token expired.");
            // update sts token and call resumeWithToken
            
            // OSS token过期,设置新的STS,继续上传
            //[weakSelf.uploader resumeWithToken:`STS Key Id` accessKeySecret:`STS Key Secret` secretToken:`STS Secret Token` expireTime:`STS Expire Time`];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                [VHVideoUploder requestUploadAuthKeyWithToekn:self.userAccessToken success:^(id  _Nullable responseObject) {
                    
                    [weakSelf.uploader resumeWithToken:responseObject[@"stsArr"][@"AccessKeyId"] accessKeySecret:responseObject[@"stsArr"][@"AccessKeySecret"]  secretToken:responseObject[@"stsArr"][@"SecurityToken"] expireTime:responseObject[@"stsArr"][@"Expiration"] ];
                    
                } failure:^(NSError *error) {
                    
                }];
            });
        };
        
        OnUploadRertyListener testRetryCallbackFunc = ^{
            NSLog(@"manager: retry begin.");
        };
        
        OnUploadRertyResumeListener testRetryResumeCallbackFunc = ^{
            NSLog(@"manager: retry begin.");
        };
        
        OnUploadStartedListener testUploadStartedCallbackFunc = ^(UploadFileInfo* fileInfo) {
            NSLog(@"upload started .");
            
        };
        
        _listener = [[VODUploadListener alloc] init];
        _listener.finish = finishedCallbackFunc;
        _listener.failure = testFailedCallbackFunc;
        _listener.progress = testProgressCallbackFunc;
        _listener.expire = testTokenExpiredCallbackFunc;
        _listener.retry = testRetryCallbackFunc;
        _listener.retryResume = testRetryResumeCallbackFunc;
        _listener.started = testUploadStartedCallbackFunc;
    }
    return _uploader;
}


#pragma mark - public

/**
 添加文件
 
 @param videoPath 视频文件路径
 @param svideoInfo 短视频上传信息
 */
- (BOOL)addFileWithVideoPath:(NSString *)videoPath
                  svideoInfo:(VHVideoUploadModel *)svideoInfo
{
    VodInfo *info = [[VodInfo alloc] init];
    info.title = svideoInfo.name;
    info.desc = svideoInfo.desc;
    return [self.uploader addFile:videoPath vodInfo:info];
}

/**
 开始上传
 
 @param accessToken VH AccessToken
 */
- (void)startWithAccessToken:(NSString *)accessToken
{
    self.userAccessToken = accessToken;
    
    [VHVideoUploder requestUploadAuthKeyWithToekn:accessToken success:^(id  _Nullable responseObject) {

        [self.uploader setKeyId:responseObject[@"stsArr"][@"AccessKeyId"] accessKeySecret:responseObject[@"stsArr"][@"AccessKeySecret"] secretToken:responseObject[@"stsArr"][@"SecurityToken"] expireTime:responseObject[@"stsArr"][@"Expiration"] listener:self.listener];

        [self.uploader start];

    } failure:^(NSError *error) {

    }];
}


/**
 暂停上传
 */
- (void)pause
{
    [self.uploader pause];
}

/**
 恢复上传
 */
- (void)resume
{
    [self.uploader resume];
}

#pragma mark - private

+ (void)requestUploadAuthKeyWithToekn:(NSString *)toekn
                              success:(nullable void (^)(id _Nullable responseObject))success
                              failure:(nullable void (^)(NSError *error))failure
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[@"access_token"] = toekn;
    [VHWebService requestWithApi:UploadAuthKey param:dict onRequestFinished:^(id data) {
        NSLog(@"request authKey response : %@",data);
        if (success) {
            success(data);
        }
    } onRequestFailed:^(NSError *error) {
        NSLog(@"request authKey error : %@",error);
        if (failure) {
            failure(error);
        }
    }];
}

@end

这个代码测试了一下没跑通,OSS SDK报错信息如下:

failed code = Forbidden.RAM, error message = You are not authorized to operate this resource, or this API does not support RAM.

然后阿里技术的童鞋说推荐使用上传地址+凭证的方式上传。查了Api错误表,搜索‘API does not support RAM’关键字,会有解释,这个Api不能用了:

’未授权,或此 API 不支持访问控制。‘

安卓端也是报这个问题,‘临时用户访问无权限,该临时用户角色扮演指定授权策略,该授权策略无权限’。

上传地址+凭证方式源码

VHVideoUploader.m

//
//  VHVideoUploader.m
//  VHUploadFramework
//
//  Created by vhall on 2019/10/15.
//  Copyright © 2019 vhall. All rights reserved.
//

#import "VHVideoUploader.h"
#import <VODUpload/VODUploadClient.h>
#import "VHVideoUploadModel.h"
#import "VHWebService.h"

@interface VHVideoUploader ()

@property (nonatomic, strong) VODUploadClient *uploader;
@property (nonatomic, strong) VODUploadListener *listener;

@property (nonatomic, copy) NSString *userAccessToken;

@property (nonatomic, copy) NSString *uploadAuth;//上传凭证
@property (nonatomic, copy) NSString *uploadAddress;//上传地址

@end

@implementation VHVideoUploader

/**
 获取SDK版本号
 */
+ (NSString *)getSDKVersion {
    return SDK_Version;
}

#pragma mark - init

- (VODUploadClient *)uploader {
    if (!_uploader) {
        _uploader = [[VODUploadClient alloc] init];
        
        __weak typeof(self)weakSelf = self;
        
        OnUploadFinishedListener finishedCallbackFunc = ^(UploadFileInfo* fileInfo, VodUploadResult* result) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"%@", [NSString stringWithFormat:@"upload success! %@", fileInfo.filePath]);
                [weakSelf finished:fileInfo result:result];
            });
        };
        
        OnUploadFailedListener testFailedCallbackFunc = ^(UploadFileInfo* fileInfo, NSString *code, NSString* message){
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"failed code = %@, error message = %@", code, message);
                NSLog(@"state %ld",(long)fileInfo.state);
                [weakSelf failed:fileInfo code:code message:message];
            });
        };
        
        OnUploadProgressListener testProgressCallbackFunc = ^(UploadFileInfo* fileInfo, long uploadedSize, long totalSize) {
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"progress uploadedSize : %li, totalSize : %li", uploadedSize, totalSize);
                [weakSelf progress:fileInfo uploadSize:uploadedSize totalSize:totalSize];
            });
        };
        
        OnUploadTokenExpiredListener testTokenExpiredCallbackFunc = ^{
            NSLog(@"token expired.");
            
            // upload auth过期,设置新的upload auth,继续上传
            // [weakSelf.uploader resumeWithAuth:`new upload auth`];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                
                [VHVideoUploader requestUploadAuthKeyWithToekn:self.userAccessToken success:^(id  _Nullable responseObject) {
                    
//                    weakSelf.uploadAuth =
//                    weakSelf.uploadAddress =
                    
                    [weakSelf.uploader resumeWithAuth:weakSelf.uploadAuth];
                    
                } failure:^(NSError *error) {
                    
                }];
            });
        };
        
        OnUploadRertyListener testRetryCallbackFunc = ^{
            NSLog(@"manager: retry begin.");
        };
        
        OnUploadRertyResumeListener testRetryResumeCallbackFunc = ^{
            NSLog(@"manager: retry begin.");
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf onResume];
            });
        };
        
        OnUploadStartedListener testUploadStartedCallbackFunc = ^(UploadFileInfo* fileInfo) {
            NSLog(@"upload started .");
            
            // 设置上传地址 和 上传凭证
            //[weakSelf.uploader setUploadAuthAndAddress:fileInfo uploadAuth:`upload auth` uploadAddress:`upload address`];

            [weakSelf.uploader setUploadAuthAndAddress:fileInfo uploadAuth:weakSelf.uploadAuth uploadAddress:weakSelf.uploadAddress];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf start:fileInfo];
            });
        };
        
        
        _listener = [[VODUploadListener alloc] init];
        _listener.finish = finishedCallbackFunc;
        _listener.failure = testFailedCallbackFunc;
        _listener.progress = testProgressCallbackFunc;
        _listener.expire = testTokenExpiredCallbackFunc;
        _listener.retry = testRetryCallbackFunc;
        _listener.retryResume = testRetryResumeCallbackFunc;
        _listener.started = testUploadStartedCallbackFunc;
    }
    return _uploader;
}


#pragma mark - public

/**
 添加文件
 
 @param videoPath 视频文件路径
 @param model 短视频上传信息
 */
- (BOOL)addFileWithVideoPath:(NSString *)videoPath
                  svideoInfo:(VHVideoUploadModel *)model
{
    return [self.uploader addFile:videoPath vodInfo:[self unPackVodInfo:model]];
}

/**
 开始上传
 
 @param accessToken VH AccessToken
 */
- (void)startWithAccessToken:(NSString *)accessToken
{
    self.userAccessToken = accessToken;
    
    [VHVideoUploader requestUploadAuthKeyWithToekn:accessToken success:^(id  _Nullable responseObject) {

//        self.uploadAuth =
//        self.uploadAddress =

        [self.uploader start];

    } failure:^(NSError *error) {

    }];
}


/**
 暂停上传
 */
- (void)pause
{
    [self.uploader pause];
}

/**
 恢复上传
 */
- (void)resume
{
    [self.uploader resume];
}

#pragma mark - private

+ (void)requestUploadAuthKeyWithToekn:(NSString *)toekn
                              success:(nullable void (^)(id _Nullable responseObject))success
                              failure:(nullable void (^)(NSError *error))failure
{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    dict[@"access_token"] = toekn;
    [VHWebService requestWithApi:UploadAuthKey param:dict onRequestFinished:^(id data) {
        NSLog(@"request authKey response : %@",data);
        if (success) {
            success(data);
        }
    } onRequestFailed:^(NSError *error) {
        NSLog(@"request authKey error : %@",error);
        if (failure) {
            failure(error);
        }
    }];
}

- (VHUploadFileInfo *)packUploadInfo:(UploadFileInfo *)fileInfo {
    VHUploadFileInfo *info = [[VHUploadFileInfo alloc] init];
    info.filePath = fileInfo.filePath;
    info.endpoint = fileInfo.endpoint;
    info.bucket = fileInfo.bucket;
    info.object = fileInfo.object;
    info.state = (VHVODUploadFileStatus)fileInfo.state;
    info.vodInfo = [self packUploadModel:fileInfo.vodInfo];
    return info;
}
- (VHVideoUploadModel *)packUploadModel:(VodInfo *)vodInfo {
    VHVideoUploadModel *info = [[VHVideoUploadModel alloc] init];
    info.title = vodInfo.title;
    info.tags = vodInfo.tags;
    info.desc = vodInfo.desc;
    info.cateId = vodInfo.cateId;
    info.coverUrl = vodInfo.coverUrl;
    info.userData = vodInfo.userData;
    return info;
}

- (VodInfo *)unPackVodInfo:(VHVideoUploadModel *)model {
    VodInfo *info = [[VodInfo alloc] init];
    info.title = model.title;
    info.tags = model.tags;
    info.desc = model.desc;
    info.cateId = model.cateId;
    info.coverUrl = model.coverUrl;
    info.userData = model.userData;
    return info;
}

- (VHVodUploadResult *)packUploadResult:(VodUploadResult *)result
{
    VHVodUploadResult *uploadResult = [[VHVodUploadResult alloc] init];
    uploadResult.videoId = result.videoId;
    uploadResult.imageUrl = result.imageUrl;
    uploadResult.bucket = result.bucket;
    uploadResult.endpoint = result.endpoint;
    return uploadResult;
}


#pragma mark - 回调
- (void)start:(UploadFileInfo *)fileInfo {
    if ([self.delegate respondsToSelector:@selector(uploader:didStarted:)]) {
        [self.delegate uploader:self didStarted:[self packUploadInfo:fileInfo]];
    }
}
- (void)failed:(UploadFileInfo *)fileInfo code:(NSString *)code message:(NSString *)message {
    if ([self.delegate respondsToSelector:@selector(failed:code:message:)]) {
        [self.delegate uploader:self didFailed:[self packUploadInfo:fileInfo] code:code message:message];
    }
}
- (void)finished:(UploadFileInfo *)fileInfo result:(VodUploadResult *)reult {
    if ([self.delegate respondsToSelector:@selector(uploader:didFinished:result:)]) {
        [self.delegate uploader:self didFinished:[self packUploadInfo:fileInfo] result:[self packUploadResult:reult]];
    }
}
- (void)onResume {
    if ([self.delegate respondsToSelector:@selector(uploaderDidResume:)]) {
        [self.delegate uploaderDidResume:self];
    }
}
- (void)progress:(UploadFileInfo *)fileInfo uploadSize:(long)uploadedSize totalSize:(long)totalSize  {
    
    
    if ([self.delegate respondsToSelector:@selector(uploader:progressFile:uploadSize:totalSize:)]) {
        [self.delegate uploader:self progressFile:[self packUploadInfo:fileInfo] uploadSize:uploadedSize totalSize:totalSize];
    }
}

@end

VHVideoUploadModel.h

//
//  VHVideoUploadModel.h
//  VHUploadFramework
//
//  Created by vhall on 2019/10/15.
//  Copyright © 2019 vhall. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, VHVODUploadFileStatus) {
    VHVODUploadFileStatusReady,
    VHVODUploadFileStatusUploading,
    VHVODUploadFileStatusCanceled,
    VHVODUploadFileStatusPaused,
    VHVODUploadFileStatusSuccess,
    VHVODUploadFileStatusFailure
};



@interface VHVideoUploadModel : NSObject

/**
 标题
 */
@property (nonatomic, copy) NSString* title;

/**
 标签
 */
@property (nonatomic, copy) NSString* tags;

/**
 描述
 */
@property (nonatomic, copy) NSString* desc;

/**
 分类id
 */
@property (nonatomic, strong) NSNumber* cateId;

/**
 封面url
 */
@property (nonatomic, copy) NSString* coverUrl;

/**
 设置自定义数据
 */
@property (nonatomic, copy) NSString* userData;

@end


@interface VHUploadFileInfo : NSObject

@property (nonatomic, copy) NSString* filePath;
@property (nonatomic, copy) NSString* endpoint;
@property (nonatomic, copy) NSString* bucket;
@property (nonatomic, copy) NSString* object;
@property (nonatomic, strong) VHVideoUploadModel* vodInfo;
@property VHVODUploadFileStatus state;

@end


@interface VHVodUploadResult: NSObject
@property (nonatomic, copy) NSString* videoId;
@property (nonatomic, copy) NSString* imageUrl;
@property (nonatomic, copy) NSString* bucket;
@property (nonatomic, copy) NSString* endpoint;
@end

NS_ASSUME_NONNULL_END

这种每次回调的时候都需要将数据包装,在progress回调方法中一直创建对象的方法不是很妥当,还需要优化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

阿里云视频点播文件上传-iOS 的相关文章

  • (16) 基于图卷积神经网络的轨道交通流量预测

    交通预见未来 16 基于图卷积神经网络的轨道交通流量预测 1 文章信息 Predicting Station Level Short Term Passenger Flow in a Citywide Metro Network Using
  • 计算机c盘突然少了几个G,做系统时c盘显示0容量-关于Windows系统c盘突然没了十几个g...

    既然系统默认装软件是c盘 那为什么不把c盘空间做大点呢 C盘是系统盘 多大容量完全是自己分出来的 你的c盘容量应该是别人给分的 一般为了电脑速度快一些 会用SSD做系统盘 你说你就一个1T的硬盘 那其实可以完全分成一个区 也就是就一个C盘
  • 如何提取OneDrive文件直链?

    原理 原链接 https xxxx my sharepoint com x g personal xx xx xx xxxxxxxxxx 直链 https xxxx my sharepoint com personal xx xx xx l
  • CNN之手写数字识别(Handwriting Recognition)

    CNN之手写数字识别 Handwriting Recognition 目录 CNN之手写数字识别 Handwriting Recognition 1 常用的包 2 常见概念 3 手写数字识别器实现 3 1 数据准备 3 2 构建网络 3 3
  • VB基础语法

    一 基础概念 1 1变量 变量的定义格式 Dim Private Static Public 变量名 As 数据类型 Dim Private Static Public 就是我之前所说的权限的意思 As 数据类型 这个是可选项 你可以为这个
  • 准备数据集

    目录 介绍 足够的数据集 收集图像 调整图像大小 下一步 在这里 我们简要说明了数据集的要求 然后 我们提出了收集数据的方法 在Internet上搜索图像 搜索视频并从中上传帧 然后 我们提供一些找到的视频的参考 然后 我们说明使用可用工具
  • defer和async的区别

    没有 defer 或 async 浏览器会立即加载并执行指定的脚本 立即 指的是在渲染该 script 标签之下的文档元素之前 也就是说不等待后续载入的文档元素 读到就加载并执行 有 async 加载和渲染后续文档元素的过程将和 scrip
  • python读取docx文件,并进行一些操作

    python读取docx文件 1 安装包 先前试用过很多包 都不管用 读取文件时候会出现如下错误 pywintypes com error 2147352567 发生意外 0 Kingsoft WPS 文档保存失败 3011 2147467
  • 从零开始学python 07——字典

    一 字典 1 字典的定义 通过 里面的数据都是以键值对保存 key value 字典中可以存在多个键值对 用逗号隔开 注意点 字典中的key一般都是字符串类型 也可以是数值类型 字典中的key一般不要相同 如果出现多个相同的key 以最后一
  • python 点名随机+人脸识别

    基于tkinter写的随机点名窗口程序 运行截图 主窗口 点名操作 人脸识别操作 具体代码如下 主窗口 import random import tkinter import tkinter as tk import threading i
  • win7安装visual studio 2015出现安装包丢失或损坏

    win r 输入 certmgr msc 查看有没有选中的两个证书 如果没有需要从其他电脑导入 然后直接点击安装界面重试 即可继续安装
  • 海关爬虫7代(圣佛版)

    声明 代码仅作学习交流用途 代码分享者与创作者不承担任何由他人恶意运行而导致的责任 勿擅自修改限制频率的参数 勿恶意攻击网页 请学习浏览者遵守社会公德与法律秩序 爬虫导致的网页崩溃等损失由计算机操作者负全部责任 造成严重后果的需要承担刑事责
  • vue顶部菜单加左侧菜单_物流项目之用户登录、主页面、顶部菜单授权

    工程搭建分析 freight parent 父工程 打包方式pom 管理jar包的版本号 所有module都应该继承父工程 为什么不在freight parent定义所有jar包 而是定义版本号呢 项目部署到tomcat需要打war包 如果

随机推荐

  • hive中distribute by、sort by、cluster by

    1 背景 hive中有一个store表 字段分别是 商店所属人标识 merid 商户余额 money 商店名称 name 求每个法人下属的商店的余额按照降序排序 merid money name B 10 store B 4 A 12 st
  • 区块链技术2---BTC的数据结构

    1 Hash pointers 哈希指针 和普通指针相比 哈希指针除了保存地址还保存哈希值 2 Block chain 区块链中的区块通过哈希指针相连 这里的哈希指针的哈希值是对前一个区块的整体取哈希值 包括前一个区块的哈希指针 因此区块链
  • python3.7安装dlib (Wind10)

    使用pip install dlib 提示失败 原因 https pypi org project dlib files 查看说明最新版本dlib 19 20 0 不支持Python3 7 解决方案 整理了下网上说的方案大致如下 一 编译安
  • android 悬浮组件实现

    项目需求 需要实现一个每个页面都存在的悬浮按钮 可以拖动 跟随整个项目的生命周期 即应用登录之后显示悬浮按钮 应用退出之后 隐藏悬浮按钮 特殊页面隐藏悬浮按钮 应用后台展示之后 隐藏悬浮按钮 应用恢复前台展示 显示悬浮按钮 准备工作 添加权
  • js提示“没有权限”的问题(转载)

    当某个互联网运营商的网站上规模之后 他们都会考虑将网站部署到主域名相同 子域名不同的服务器集群上 以此来构建一个聚合的应用 同时 希望能够利用 JavaScript 在不同子域的网页间相互操作 实现一个对用户来说 无缝 的应用 这时 跨域操
  • 我是如何用 redis 分布式锁来解决线上历史业务问题的

    近期发现 开发功能的时候发现了一个 mq 消费顺序错乱 历史遗留问题 导致业务异常的问题 看看我是如何解决的 问题抛出 首先 简单介绍一下情况 线上 k8s 有多个 pod 会去消费 mq 中的消息 可是生产者发送的消息是期望一定要有序去消
  • HTML5 postMessage和跨域通信

    HTML5 postMessage和跨域通信 http iknowledge wikispaces com HTML5 postMessage E5 92 8C E8 B7 A8 E5 9F 9F E9 80 9A E4 BF A1 HTM
  • stm32cubemx hal学习记录:FreeRTOS中断管理

    一 参数配置 1 配置RCC USART1 时钟84M 2 配置SYS 将Timebase Source修改为除滴答定时器外的其他定时器 3 初始化LED的两个引脚 两个按键引脚 4 开启FreeRTOS v1与v2版本不同 一般选用v1即
  • 梯度下降法及其Python实现

    梯度下降法 gradient descent 又名最速下降法 steepest descent 是求解无约束最优化问题最常用的方法 它是一种迭代方法 每一步主要的操作是求解目标函数的梯度向量 将当前位置的负梯度方向作为搜索方向 因为在该方向
  • 轻松玩转开源大语言模型bloom(一)

    前言 chatgpt已经成为了当下热门 github首页的trending排行榜上天天都有它的相关项目 但背后隐藏的却是openai公司提供的api收费服务 作为一名开源爱好者 我非常不喜欢知识付费或者服务收费的理念 所以便有决心写下此系列
  • Vue3最常见的10道面试题:含答案和代码示例的练习题

    本文列举了10道Vue3面试题 每道题都包含了答案和代码示例 希望对你的面试有所帮助 什么是Vue3 Vue3是Vue js的下一个主要版本 它带来了很多重要的改进和新功能 包括更快的渲染速度 更好的类型支持 更好的组合API等 什么是Co
  • Postman 如何调用文件上传下载接口

    文件导入导出是管理后台的通用功能 所以在接口写好后在没有前端页面使用Postman进行接口调用测试接口功能成为一个选择 导出 在我们输入接口地址 token等候 点击send 发现下载的成为了乱码 如下图 这明显不符合我们的预期期望 在se
  • 文本分析简历项目收集-----机器学习(仅供参考)

    文本分析 项目3 基于自然语言处理的影评分析 项目简介 通过大量的正面和负面的电影评论对计算机进行自然语言训练 实现计算机对电影评论的基本情感分析 使其能够快速判断出评论是否积极 个人职责 1 对正面和负面的电影评论进行分词处理 整理成规定
  • 一次让人难以忘怀的排查频繁Full GC过程

    我们的Java应用因频繁FULL GC导致性能降低很多 经过多人的定位也没有结论 于是我自主请命 经过一天的研究终于搞定了 现把经验与大家共享 相关的gc日志如下 4 758 Full GC PSYoungGen 464K gt 0K 71
  • linux统计一个文件中特定字符的个数

    统计一个文件中某个字符串的个数 其实就是在在一块沙地里面找石头 有的人看到石头以后 在上面做个标记 grep 然后记住自己做了多少个标记 有的 人看到石头以后 把它挖了 tr 最后统计自己挖了多少石头 有的人看到石头以后 把它跳过去 awk
  • STL:list的模拟实现(迭代器失效探讨)

    为什么重新设计list迭代器 对迭代器解引用 我们希望拿到的是指针所指向的值域 而直接解引用拿到的是指针所指向的节点 对list指针 和 迭代器 提供一种方法 使其能够按照顺序访问容器 聚合物 所含的各个元素 并且不用暴露容器内部的表述方式
  • 达芬奇15中文版

    教程 1 下载解压 得到davinci resolve 15原程序和文件 2 双击文件 DaVinci Resolve Studio 15 0b2 Windows exe 依提示安装原程序 3 达芬奇软件需要安装必要的组件 一般按默认安装即
  • Flexible弹性布局

    flex布局 弹性布局 flex的两个重要概念 开启了flex布局的元素叫flex container display flex inline flex flex container 里面的直接子元素叫做 flex items flex布局
  • 来源查询检索的研究

    来源查询检索的研究 来源查询的方式主要有 基于内容索引的查询 gt 基于时间局部性的上下文增强搜索查询 gt 基于因果关系的查询 根据provenance提供上下文有关的索引 即因果关系 1 传统的来源查询检索方式为基于内容索引的查询 在这
  • 阿里云视频点播文件上传-iOS

    文章目录 阿里云视频点播文件上传 iOS 一 上传方式 方式一 上传地址加凭证上传 1 请求AppServer 2 在start的回调中设置上传地址和上传凭证 3 uploadAuth过期重新设置 4 上传图片和上传视频 方式二 STS方式