iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >AVFoundationAVCaptureSession媒体捕捉
  • 791
分享到

AVFoundationAVCaptureSession媒体捕捉

摘要

目录正文捕捉媒体1.创建会话2.配置视频输入3.配置音频输入5.配置输出6.开始会话\结束会话7.捕捉静态图片8.捕捉视频文件9.预览视频正文 AVFoundation 是Apple

正文

AVFoundation 是Apple iOS和OS X系统中用于处理基于时间的媒体数据的高级框架,通过开发所需的工具提供了强大的功能集,让开发者能够基于苹果平台创建当下最先进的媒体应用程序,其针对64位处理器设计,充分利用了多核硬件优势,会自动提供硬件加速操作,确保大部分设备能以最佳性能运行,是iOS开发接触音视频开发必学的框架之一

参与掘金日新计划,持续记录AVFoundation学习,Demo学习地址,里面封装了一些工具类,可以直接使用,这篇文章主要讲述AVFoundation中的AVCaptureSession等类实现媒体捕捉功能,其他类的相关用法可查看我的其他文章。

捕捉媒体

媒体捕捉是AVFoundation的核心功能之一,也是开发音视频App必不可少的功能。捕捉用到的类如图所示

  • AVCaptureSession是AVFoundation捕捉栈的核心类,捕捉会话用于连接输入和输出资源,管理从物理设备得到的输入流,例如从摄像头得到的视频从麦克风得到的音频,以不同的方式输出给一个或多个输出,可以动态配置输入和输出线路,让开发者能够在会话中按需重新配置捕捉环境。
  • AVCaptureDevice为摄像头麦克风等物理设备定义了一个接口,在iOS10以后,使用AVCaptureDeviceDiscoverySession获取设备。
  • AVCaptureDevice包装成AVCaptureDeviceInput才能添加到捕捉回话中。
  • AVFoundation定义了AVCaptureOutput的许多扩展类,AVCaptureOutput是一个抽象基类,用于从捕捉回话中得到数据,框架定义了这个抽象类的高级扩展类,常用的有AVCaptureStillImageOutput静态图片输出、AVCaptureMovieFileOutput视频文件输出、AVCaptureVideoDataOutput视频流数据输出、AVCaptureAudioDataOutput音频流数据输出、AVCaptureMetadataOutput元数据输出。注意,不能同时配置AVCaptureVideoDataOutputAVCaptureMovieFileOutput,二者无法同时启用。
  • AVCaptureVideoPreviewLayer是CoreAnimation框架中CALayer的一个子类,对捕捉视频数据实时预览。当然也可以使用GLKViewUIImageView预览实时视频流的Buffer。

具体代码可以看Demo中的CQCaptureManager类对捕捉工具的封装

1.创建会话

创建会话并配置分辨率

  • 配置分辨率注意要判断下能否支持,例如老机型前置摄像头配置4k是不支持的。
  • 不同分辨率的缩放倍数也是不同的
self.captureSession = [[AVCaptureSession alloc] init];
- (void)configSessionPreset:(AVCaptureSessionPreset)sessionPreset {
    [self.captureSession beginConfiguration];
    if ([self.captureSession canSetSessionPreset:sessionPreset])  {
        self.captureSession.sessionPreset = sessionPreset;
    } else {
        self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
    }
    [self.captureSession commitConfiguration];
    self.isConfigSessionPreset = YES;
}

2.配置视频输入

/// 配置视频输入
- (BOOL)configVideoInput:(NSError * _Nullable *)error {
    // 添加视频捕捉设备
    // 拿到默认视频捕捉设备 iOS默认后置摄像头
//    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDevice *videoDevice = [self getCameraWithPosition:AVCaptureDevicePositionBack];
    // 将捕捉设备转化为AVCaptureDeviceInput
    // 注意:会话不能直接使用AVCaptureDevice,必须将AVCaptureDevice封装成AVCaptureDeviceInput对象
    AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:error];
    // 将捕捉设备添加给会话
    // 使用前判断videoInput是否有效以及能否添加,因为摄像头是一个公共设备,不属于任何App,有可能别的App在使用,添加前应该先进行判断是否可以添加
    if (videoInput && [self.captureSession canAddInput:videoInput]) {
        // 将videoInput 添加到 captureSession中
        [self.captureSession beginConfiguration];
        [self.captureSession addInput:videoInput];
        [self.captureSession commitConfiguration];
        self.videoDeviceInput = videoInput;
        return YES;
    }else {
        return NO;
    }
}
/// 移除视频输入设备
- (void)removeVideoDeviceInput {
    if (self.videoDeviceInput) [self.captureSession removeInput:self.videoDeviceInput];
    self.videoDeviceInput = nil;
}
  • 获取摄像头,iOS10之后使用AVCaptureDeviceDiscoverySession获取
  • 长焦超广或者双摄三摄必须使用AVCaptureDeviceDiscoverySession获取,[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]无法获取
/// 根据position拿到摄像头
- (AVCaptureDevice *)getCameraWithPosition:(AVCaptureDevicePosition)position {
    
    NSArray *deviceTypes;
    if (position == AVCaptureDevicePositionBack) {
        deviceTypes = @[AVCaptureDeviceTypeBuiltInDualCamera,
                        AVCaptureDeviceTypeBuiltInDualWideCamera,
                        AVCaptureDeviceTypeBuiltInTripleCamera, ];
    } else {
        deviceTypes = @[AVCaptureDeviceTypeBuiltInWideangleCamera];
    }
    AVCaptureDeviceDiscoverySession *deviceSession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:position];
    if (deviceSession.devices.count) return deviceSession.devices.firstObject;
    if (position == AVCaptureDevicePositionBack) {
        // 非多摄手机
        deviceTypes = @[AVCaptureDeviceTypeBuiltInWideAngleCamera];
        AVCaptureDeviceDiscoverySession *deviceSession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:deviceTypes mediaType:AVMediaTypeVideo position:position];
        if (deviceSession.devices.count) return deviceSession.devices.firstObject;
    }
    return nil;
}

3.配置音频输入

/// 配置音频输入
- (BOOL)configAudioInput:(NSError * _Nullable *)error {
    // 添加音频捕捉设备 ,如果只是拍摄静态图片,可以不用设置
    // 选择默认音频捕捉设备 即返回一个内置麦克风
    AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    self.audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:error];
    if (self.audioDeviceInput && [self.captureSession canAddInput:self.audioDeviceInput]) {
        [self.captureSession beginConfiguration];
        [self.captureSession addInput:self.audioDeviceInput];
        [self.captureSession commitConfiguration];
        return YES;
    }else {
        return NO;
    }
}
/// 移除音频输入设备
- (void)removeAudioDeviceInput {
    if (self.audioDeviceInput) [self.captureSession removeInput:self.audioDeviceInput];
}

5.配置输出

#pragma mark - Func 静态图片输出配置
/// 配置静态图片输出
- (void)configStillImageOutput {
    // AVCaptureStillImageOutput 从摄像头捕捉静态图片
    self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    // 配置字典:希望捕捉到JPEG格式的图片
    self.stillImageOutput.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    // 输出连接 判断是否可用,可用则添加到输出连接中去
    [self.captureSession beginConfiguration];
    if ([self.captureSession canAddOutput:self.stillImageOutput]) {
        [self.captureSession addOutput:self.stillImageOutput];
    }
    [self.captureSession commitConfiguration];
}
/// 移除静态图片输出
- (void)removeStillImageOutput {
    if (self.stillImageOutput) [self.captureSession removeOutput:self.stillImageOutput];
}
#pragma mark - Func 电影文件输出配置
/// 配置电影文件输出
- (void)configMovieFileOutput {
    // AVCaptureMovieFileOutput,将QuickTime视频录制到文件系统
    self.movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
    [self.captureSession beginConfiguration];
    if ([self.captureSession canAddOutput:self.movieFileOutput]) {
        [self.captureSession addOutput:self.movieFileOutput];
    }
    [self.captureSession commitConfiguration];
}
/// 移除电影文件输出
- (void)removeMovieFileOutput {
    if (self.movieFileOutput) [self.captureSession removeOutput:self.movieFileOutput];
}

6.开始会话\结束会话

// 异步开始会话
- (void)startSessionAsync {
    // 检查是否处于运行状态
    if (![self.captureSession isRunning]) {
        // 使用同步调用会损耗一定的时间,则用异步的方式处理
        dispatch_async(self.captureVideoQueue, ^{
            [self.captureSession startRunning];
        });
    }
}
// 异步停止会话
- (void)stopSessionAsync {
    // 检查是否处于运行状态
    if ([self.captureSession isRunning]) {
        dispatch_async(self.captureVideoQueue, ^{
            [self.captureSession stopRunning];
        });
    }
}

7.捕捉静态图片

#pragma mark - 静态图片捕捉
#pragma mark Public Func 静态图片捕捉
// 捕捉静态图片
- (void)captureStillImage {
    if (!self.isConfigSessionPreset) [self configSessionPreset:AVCaptureSessionPresetMedium];
    if (!self.videoDeviceInput) {
        NSError *configError;
        BOOL configResult = [self configVideoInput:&configError];
        if (!configResult) return;
    }
    if (!self.stillImageOutput) [self configStillImageOutput];
    [self startSessionSync];
    // 获取图片输出连接
    AVCaptureConnection *connection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    // 即使程序只支持纵向,但是如果用户横向拍照时,需要调整结果照片的方向
    // 判断是否支持设置视频方向, 支持则根据设备方向设置输出方向值
    if (connection.isVideoOrientationSupported) {
        connection.videoOrientation = [self getCurrentVideoOrientation];
    }
    [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef  _Nullable imageDataSampleBuffer, NSError * _Nullable error) {        if (imageDataSampleBuffer != NULL) {            dispatch_async(dispatch_get_main_queue(), ^{                if (self.delegate && [self.delegate respondsToSelector:@selector(mediaCaptureImageFileSuccess)]) {
                    [self.delegate mediaCaptureImageFileSuccess];
                }
            });
            // CMSampleBufferRef转UIImage 并写入相册
            NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [[UIImage alloc] initWithData:imageData];
            [self writeImageToAssetsLibrary:image];
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.delegate && [self.delegate respondsToSelector:@selector(mediaCaptureImageFailedWithError:)]) {
                    [self.delegate mediaCaptureImageFailedWithError:error];
                }
            });
            NSLog(@"NULL sampleBuffer:%@",[error localizedDescription]);
        }
    }];
}
#pragma mark Private Func 静态图片捕捉

/// 将UIImage写入到用户相册
- (void)writeImageToAssetsLibrary:(UIImage *)image {
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    // 参数1 图片, 参数2 方向, 参数3 回调
    [library writeImageToSavedPhotosAlbum:image.CGImage orientation:(NSUInteger)image.imageOrientation completionBlock:^(NSURL *assetURL, NSError *error) {        if (!error) {            dispatch_async(dispatch_get_main_queue(), ^{                if (self.delegate && [self.delegate respondsToSelector:@selector(assetLibraryWriteImageSuccessWithImage:)]) {
                    [self.delegate assetLibraryWriteImageSuccessWithImage:image];
                }
            });
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.delegate && [self.delegate respondsToSelector:@selector(assetLibraryWriteImageFailedWithError:)]) {
                    [self.delegate assetLibraryWriteImageFailedWithError:error];
                }
            });
        }
    }];
}

8.捕捉视频文件

#pragma mark - 电影文件捕捉
#pragma mark Public Func 电影文件捕捉
// 开始录制电影文件
- (void)startRecordingMovieFile {
    if (!self.isConfigSessionPreset) [self configSessionPreset:AVCaptureSessionPresetMedium];
    if (!self.videoDeviceInput) {
        NSError *configError;
        BOOL configResult = [self configVideoInput:&configError];
        if (!configResult) return;
    }
    if (!self.movieFileOutput) [self configMovieFileOutput];
    [self startSessionSync];
    if ([self isRecordingMovieFile]) return;
    AVCaptureConnection *videoConnection = [self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    // 设置输出方向
    // 即使程序只支持纵向,但是如果用户横向拍照时,需要调整结果照片的方向
    // 判断是否支持设置视频方向, 支持则根据设备方向设置输出方向值
    if (videoConnection.isVideoOrientationSupported) {
        videoConnection.videoOrientation = [self getCurrentVideoOrientation];
    }
    // 设置视频帧稳定
    // 判断是否支持视频稳定 可以显著提高视频的质量。只会在录制视频文件涉及
//    if (videoConnection.isVideoStabilizationSupported) {
//        videoConnection.enablesVideoStabilizationWhenAvailable = YES;
//    }
    videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
    // 设置对焦
    AVCaptureDevice *device = [self getActiveCamera];
    // 摄像头可以进行平滑对焦模式操作。即减慢摄像头镜头对焦速度。当用户移动拍摄时摄像头会尝试快速自动对焦。
    if (device.iSSMoothAutoFocusEnabled) {
        NSError *error;
        if ([device lockForConfiguration:&error]) {
            device.smoothAutoFocusEnabled = YES;
            [device unlockForConfiguration];
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.delegate && [self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
                    [self.delegate deviceConfigurationFailedWithError:error];
                }
            });
        }
    }
    self.movieFileOutputURL = [self getVideoTempPathURL];
    // 开始录制 参数1:录制保存路径  参数2:代理
    [self.movieFileOutput startRecordingToOutputFileURL:self.movieFileOutputURL recordingDelegate:self];
}
// 停止录制电影文件
- (void)stopRecordingMovieFile {
    if ([self isRecordingMovieFile]) {
        [self.movieFileOutput stopRecording];
    }
}
// 是否在录制电影文件
- (BOOL)isRecordingMovieFile {
    return self.movieFileOutput.isRecording;
}
// 录制电影文件的时间
- (CMTime)movieFileRecordedDuration {
    return self.movieFileOutput.recordedDuration;
}
#pragma mark AVCaptureFileOutputRecordingDelegate
/// 捕捉电影文件成功的回调
- (void)captureOutput:(AVCaptureFileOutput *)output didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections error:(NSError *)error {
    if (error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.delegate && [self.delegate respondsToSelector:@selector(mediaCaptureMovieFileFailedWithError:)]) {
                [self.delegate mediaCaptureMovieFileFailedWithError:error];
            }
        });
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.delegate && [self.delegate respondsToSelector:@selector(mediaCaptureMovieFileSuccess)]) {
                [self.delegate mediaCaptureMovieFileSuccess];
            }
        });
        // copy一个副本再置为nil
        // 将文件写入相册
        [self writeVideoToAssetsLibrary:self.movieFileOutputURL.copy];
        self.movieFileOutputURL = nil;
    }
}
#pragma mark Private Func 电影文件捕捉
/// 创建视频文件临时路径URL
- (NSURL *)getVideoTempPathURL {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *tempPath = [fileManager temporaryDirectoryWithTemplateString:@"video.XXXXXX"];
    if (tempPath) {
        NSString *filePath = [tempPath stringByAppendingPathComponent:@"temp_video.mov"];
        return [NSURL fileURLWithPath:filePath];
    }
    return nil;
}
/// 将视频文件写入到用户相册
- (void)writeVideoToAssetsLibrary:(NSURL *)videoURL {
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    // 和图片不同,视频的写入更耗时,所以写入之前应该判断是否能写入
    if (![library videoAtPathIsCompatibleWithSavedPhotosAlbum:videoURL]) return;
    [library writeVideoAtPathToSavedPhotosAlbum:videoURL completionBlock:^(NSURL *assetURL, NSError *error) {
        if (error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                if (self.delegate && [self.delegate respondsToSelector:@selector(assetLibraryWriteMovieFileFailedWithError:)]) {
                    [self.delegate assetLibraryWriteMovieFileFailedWithError:error];
                }
            });
        } else {
            // 写入成功 回调封面图
            [self getVideoCoverImageWithVideoURL:videoURL callBlock:^(UIImage *coverImage) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (self.delegate && [self.delegate respondsToSelector:@selector(assetLibraryWriteMovieFileSuccessWithCoverImage:)]) {
                        [self.delegate assetLibraryWriteMovieFileSuccessWithCoverImage:coverImage];
                    }
                });
            }];
        }
    }];
}
/// 获取视频文件封面图
- (void)getVideoCoverImageWithVideoURL:(NSURL *)videoURL callBlock:(void(^)(UIImage *))callBlock {
    dispatch_async(self.captureVideoQueue, ^{
        AVAsset *asset = [AVAsset assetWithURL:videoURL];
        AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
        // 设置maximumSize 宽为100,高为0 根据视频的宽高比来计算图片的高度
        imageGenerator.maximumSize = CGSizeMake(100.0f, 0.0f);
        // 捕捉视频缩略图会考虑视频的变化(如视频的方向变化),如果不设置,缩略图的方向可能出错
        imageGenerator.appliesPreferredTrackTransfORM = YES;
        CGImageRef imageRef = [imageGenerator copyCGImageAtTime:kCMTimeZero actualTime:NULL error:nil];
        UIImage *image = [UIImage imageWithCGImage:imageRef];
        CGImageRelease(imageRef);
        dispatch_async(dispatch_get_main_queue(), ^{
            !callBlock ?: callBlock(image);
        });
    });
}

9.预览视频

previewView.session = captureManager.captureSession

以上就是AVFoundation AVCaptureSession媒体捕捉的详细内容,更多关于AVFoundation AVCaptureSession的资料请关注编程网其它相关文章!

--结束END--

本文标题: AVFoundationAVCaptureSession媒体捕捉

本文链接: https://www.lsjlt.com/news/170210.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • AVFoundationAVCaptureSession媒体捕捉
    目录正文捕捉媒体1.创建会话2.配置视频输入3.配置音频输入5.配置输出6.开始会话\结束会话7.捕捉静态图片8.捕捉视频文件9.预览视频正文 AVFoundation 是Apple...
    99+
    2022-11-13
    AVFoundation AVCaptureSession媒体捕捉 AVFoundation AVCaptureSession
  • golang错误捕捉
    Golang是一种强类型的编程语言,它在语言级别提供了良好的错误处理机制。错误处理是Golang开发过程中必不可少的一部分,它的设计理念是将错误处理从代码中与业务逻辑分离,以达到更加可读、可维护的代码。在Golang中,错误机制的基础是一个...
    99+
    2023-05-16
  • python 捕捉所有异常
    原文链接:http://blog.csdn.net/yangchao228/article/details/7425410如果你在写程序时遇到异常后想进行如下处理的话请参考我下面写的对异常处理的方法:假设有下面的一段程序:try:    语...
    99+
    2023-01-31
    异常 python
  • react native 怎么捕捉错误
    本教程操作环境:Windows10系统、react18.0.0版、Dell G3电脑。react native 怎么捕捉错误?React Native错误捕捉与处理经常使用发行包进行测试的开发者们可能会发现,在发行版本中,如果出现了脚本错误...
    99+
    2023-05-14
    react-native
  • Python之捕捉异常详解
    目录1.python中的异常2.捕捉异常try-except多个except子句 一个except块捕捉多个异常 空except:捕捉所有异常as语句: else语句:finally...
    99+
    2024-04-02
  • Linux如何实现信号捕捉
    这篇文章主要介绍了Linux如何实现信号捕捉,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。##signal函数函数原型:sighandler_t signal(in...
    99+
    2023-06-15
  • react native如何捕捉错误
    这篇文章主要介绍“react native如何捕捉错误”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“react native如何捕捉错误”文章能帮助大家解决问题。react native捕捉错误的方...
    99+
    2023-07-04
  • Android 是如何捕捉 java 异常的
    目录一、java异常全局捕捉二、小知识1、如何捕获异常不退出2、如何捕获指定线程异常3、ThreadGroup和Thread的关系结构一、 java 异常全局捕捉 用于 java 异...
    99+
    2024-04-02
  • faststone capture怎么捕捉固定区域
    这篇文章主要介绍了faststone capture怎么捕捉固定区域的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇faststone capture怎么捕捉固定区域文章都会有所收获,下面我们一起来看看吧。fas...
    99+
    2023-07-06
  • Python捕捉异常举例分析
    这篇文章主要讲解了“Python捕捉异常举例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python捕捉异常举例分析”吧!1.python中的异常语法错误:没有按照语法规则书写程序运行...
    99+
    2023-06-21
  • c#中nmodbus如何捕捉异常
    在C#中,可以使用try-catch语句块来捕捉Modbus通信中的异常。以下是一个示例代码,演示如何捕捉Modbus异常: usi...
    99+
    2024-04-02
  • python如何捕捉屏幕上的文字
    要捕捉屏幕上的文字,你可以使用Python中的pytesseract库。pytesseract是一个OCR(光学字符识别)库,可以用...
    99+
    2023-10-18
    python
  • 用Python捕捉和模拟鼠标事件
    这个假期玩了不少galgame,不过有些很老的游戏没有自动运行模式,点击鼠标又太伤按键了,于是想把滚动鼠标滚轮映射为点击鼠标。 网上搜了一下,没发现...
    99+
    2023-01-31
    鼠标 事件 Python
  • Javascript中async与await的捕捉错误详解
    目录async与await捕捉错误正常的输出时try catch捕捉错误多个异步嵌套时 await-to-js异步嵌套使用了try,代码相对不够智能总结async与awai...
    99+
    2024-04-02
  • VB.NET中怎么实现异常迭代捕捉
    VB.NET中怎么实现异常迭代捕捉,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。VB.NET异常迭代捕捉代码示例:Dim a As Integer...
    99+
    2023-06-17
  • Python异常对象Exception基础类异常捕捉
    目录异常对象异常捕捉异常对象 Python中遇到错误后,会引发异常。 Python中使用异常对象来表示异常情况。 如果异常对象未被处理或者捕捉,程序就会用所谓的回溯(tracebac...
    99+
    2024-04-02
  • oracle存储过程异常如何捕捉
    在Oracle中,可以使用异常处理来捕获存储过程中的异常。在存储过程中,可以使用以下语句来捕获异常并进行处理:sqlDECLARE ...
    99+
    2023-10-25
    oracle
  • golang的panic为什么主进程捕捉不到
    主进程无法捕捉到 go 中发生的 panic,原因是异步执行(goroutine)。解决方法包括:使用 recovery 函数捕获和恢复 panic。使用 context 包将值传递给 ...
    99+
    2024-04-21
    golang
  • python 捕捉和模拟鼠标键盘操作
    最近老师布置了一个作业,要求我们建立一个6位数字的gmail账号,然而我脸太黑,试了好多次都不成功,于是决定用python来写一个脚本遍历输入所有6位数。这就要求掌握使用python捕捉和模拟键盘操作了,于是我查阅了网上诸多资料...
    99+
    2023-01-31
    鼠标键盘 操作 python
  • koa怎么进行错误捕捉和返回
    这篇文章主要介绍了koa怎么进行错误捕捉和返回,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。示例:const Koa =...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作