Java与AWS S3的文件操作

从零开始:Java与AWS S3的文件操作

  • 一、什么是 AWS S3?
    • AWS S3 的特点
    • AWS S3 的应用场景
  • 二、Java整合S3方法
    • 使用 MinIO 客户端操作 S3
    • 使用 AWS SDK 操作 S3 (推荐使用)
  • 三、总结


一、什么是 AWS S3?

Amazon Simple Storage Service(简称 Amazon S3)是由亚马逊网络服务(AWS)提供的一种对象存储服务。它提供了一个高度可扩展、持久、安全且低成本的存储解决方案,用于存储和检索任意数量的数据。

AWS S3 的特点

  1. 高可用性和持久性:
  • AWS S3 的设计目标是为存储的数据提供 99.999999999%(11个9)的持久性,并确保 99.99% 的可用性。

  • 数据会自动在多个地理位置冗余存储,以保证数据的高持久性和可用性。

  1. 安全性:
  • AWS S3 提供了多种安全措施,包括传输中和存储时的数据加密、细粒度的访问控制策略、以及与 AWS Identity and Access Management (IAM) 集成的用户认证机制。
  1. 可扩展性:
  • AWS S3 可以自动扩展以处理从几字节到数十亿字节的数据。

  • 用户无需预先配置存储容量,且可以根据需要动态增加或减少存储容量。

  1. 成本效益:
  • AWS S3 提供按需付费的计费模式,根据实际使用量收费,没有预付费用或最低消费。

  • 用户可以选择不同的存储类别(如标准存储、智能分层存储、归档存储等),以优化存储成本。

  1. 简单易用:
  • AWS S3 提供了简单的 REST 和 SOAP API,开发人员可以方便地进行集成和操作。

  • AWS S3 管理控制台提供了直观的用户界面,用于管理存储桶和对象。

  1. 灵活的数据管理:
  • 支持版本控制、生命周期管理、事件通知和跨区域复制等高级功能,帮助用户更好地管理数据。
  1. 高效的上传和下载速度:
  • AWS S3 提供了高效的数据传输速度,支持大规模数据的快速上传和下载。

  • 上传速度:在良好的网络条件下,单个文件的上传速度可以达到数百兆比特每秒 (Mbps)

  • 下载速度:下载速度也可以达到数百兆比特每秒 (Mbps),尤其是在使用 Amazon CloudFront 进行内容分发时。

  • S3 Transfer Acceleration:通过启用 S3 Transfer Acceleration,可以进一步提升上传速度,全球范围内的传输速度可以提高 50-500% 以上,具体提升取决于用户的地理位置和网络条件。

AWS S3 的应用场景

  1. 静态网站托管:
  • AWS S3 可以用于托管静态网站,包括 HTML、CSS、JavaScript 文件等。
  1. 备份和恢复:
  • 作为企业级备份解决方案,AWS S3 可以用于存储备份数据,支持高持久性和快速恢复。
  1. 大数据分析:
  • 数据湖:AWS S3 可以作为数据湖,用于存储和分析大规模的结构化和非结构化数据。

  • 与 AWS 分析服务(如 Amazon Redshift、Amazon Athena)集成,进行大数据分析。

  1. 媒体存储和分发:
  • AWS S3 可以存储大量的媒体文件(如图片、视频、音频),并通过 Content Delivery Network (CDN) 进行全球分发。
  1. 日志存储:
  • 服务器和应用程序的日志可以存储在 AWS S3 中,以便于后续的分析和监控。
  1. 软件分发:
  • 企业可以使用 AWS S3 进行软件包和应用程序更新的分发。
  1. 容灾和跨区域复制:
  • 利用跨区域复制功能,企业可以在多个地理位置间复制数据,提高容灾能力。

二、Java整合S3方法

在 Java 中,可以通过两种主要方法与 S3 服务器进行交互:使用 MinIO 客户端和使用 AWS SDK。两者都能与 S3 服务兼容,但它们在使用方式和配置上有所不同。

使用 MinIO 客户端操作 S3

MinIO 是一个兼容 S3 API 的开源对象存储解决方案。它提供了与 AWS S3 相同的接口,因此可以使用 MinIO 的 SDK 来操作 S3 存储服务。MinIO 客户端非常适合在本地部署的 S3 兼容存储(如 MinIO 自身)和 AWS S3 上进行文件操作。

优点:

  • 轻量级、开源,适合本地部署或私有云环境。

  • 与 AWS S3 完全兼容,支持所有 S3 操作(如上传、下载、删除文件等)。

  1. 添加依赖
        <!--   S3存储服务依赖 minio    --><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.5.5</version></dependency>
  1. 配置AWS S3相关的信息
import io.minio.MinioClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;/*** @CreateTime: 2024/05/31  18:17* @Description: S3配置文件* @Version: 1.0*/
@Component
public class S3Config {@Value("${spring.s3_config.bucket_name}")private String bucketName;@Value("${spring.s3_config.endpoint}")private String s3Endpoint;@Value("${spring.s3_config.aws_access_key_id}")private String awsAccessKeyId;@Value("${spring.s3_config.aws_secret_access_key}")private String awsSecretAccessKey;private MinioClient minioClient;@PostConstructpublic void init() {// 初始化 MinioClient,minioClient = MinioClient.builder().endpoint(s3Endpoint)// s3服务器端点地址.credentials(awsAccessKeyId, awsSecretAccessKey)// 设置 访问凭证.build();}/***  获取桶名*/public String getBucketName() {return bucketName;}/***  获取minio客户端*/public MinioClient getMinioClient() {return minioClient;}
}
  1. 生成 S3 预览链接
	/*** @description: 生成 S3 预览链接* @param realPath 生成 S3 预览链接的真实地址* @return 如果成功生成预览链接则返回链接字符串,否则返回 null*/public static String generatePreviewUrl(String realPath) {try {// 创建额外的请求参数,这里设置响应内容类型Map<String, String> reqParams = new HashMap<>();String contentType = FileEnum.getByExtension(realPath.substring(realPath.lastIndexOf(".") + 1)).getContentType();reqParams.put("response-content-type", contentType);// 使用 MinIO 客户端生成预签名的对象 URLreturn minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET) // 指定请求方法为 GET.bucket(bucketName) // 指定存储桶名称.object(realPath) // 指定对象名称.extraQueryParams(reqParams) // 添加额外的查询参数(这里是响应内容类型).expiry(7, TimeUnit.DAYS) // 指定预签名 URL 的有效期.build());} catch (Exception e) {// 捕获并打印任何异常log.error("生成预览链接失败: " + e);throw new RuntimeException("生成预览链接失败");}}
  1. 上传文件到S3
 	/*** @description: 上传文件到S3* @param file 上传的文件* @return 如果成功上传返回 true,否则返回 false*/public static String uploadFile(MultipartFile file) {try {// 获取上传的文件String fileName = file.getOriginalFilename();// 参数验证:确保文件名不为空if (fileName == null || fileName.isEmpty()) {throw new ServiceException("文件名无效");}String path = projectPath + fileName;// 使用 MinIO 客户端将文件上传到 S3 存储桶try (InputStream fileStream = file.getInputStream()) {minioClient.putObject(PutObjectArgs.builder().bucket(bucketName) // 指定存储桶名称.object(path) // 指定对象名称.stream(fileStream, file.getSize(), -1) // 输入流和大小.build());}return path;} catch (Exception e) {// 捕获并打印 MinIO 异常信息log.error("上传文件失败: " + e);throw new RuntimeException("上传文件失败");}}
  1. 删除 S3 文件
  	/*** @description: 删除 S3 文件* @param fileUrl 要删除的文件的 URL 或对象名称*/public static void removeFile(String realPath) {try {// 使用 MinIO 客户端删除对象minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName) // 指定存储桶名称.object(realPath) // 指定要删除的对象名称或 URL.build());} catch (Exception e) {log.error("文件删除失败: " + e);throw new RuntimeException("文件删除失败");}}
  1. 从s3获取文件流

当在大批量并发获取大文件流时,minio的方式可能会出现获取缓慢、卡死或中断的情况,推荐采用第二种方法AWS SDK的方式去获取文件流

	/*** @description: 通过realPath获取文件流* @param: realPath* @return: InputStream **/public static InputStream downloadByS3Url(String realPath) throws IOException {try {// 获取文件流InputStream fis= minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(realPath).build());return fis;} catch (Exception e) {log.error("获取文件流失败: " + e);throw new RuntimeException("获取文件流失败");}}
  1. 从s3下载文件
	/*** 下载文件* @param filePath MinIO 中的文件路径* @param downloadPath 本地下载路径*/public static void downloadFile(String filePath, String downloadPath) {try {// 使用 getObject 获取文件InputStream fileStream = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName) // 指定存储桶名称.object(filePath)    // 指定文件路径.build());// 将文件内容写入到本地文件Path path = Paths.get(downloadPath);Files.copy(fileStream, path);System.out.println("文件已成功下载到: " + downloadPath);} catch (MinioException e) {log.error("下载文件失败: " + e);throw new RuntimeException("MinIO 下载文件失败");} catch (IOException e) {log.error("保存文件到本地时失败: " + e);throw new RuntimeException("保存文件到本地时失败");}}

使用 AWS SDK 操作 S3 (推荐使用)

AWS SDK 是 Amazon 提供的官方库,用于与 AWS 服务(包括 S3)进行交互。它不仅支持 AWS S3,还能支持其他 AWS 服务(如 EC2、DynamoDB 等)。如果你使用的是 AWS S3 或希望利用 AWS 的其它功能,AWS SDK 是推荐的选择。

优点:

  • 官方支持,功能全面,适用于使用 AWS 云服务的场景。

  • 可以访问 AWS 特有的功能和工具。

  1. 添加依赖
        <!--   S3存储服务依赖 AWS SDK    --><dependency><groupId>software.amazon.awssdk</groupId><artifactId>s3</artifactId><version>2.17.85</version></dependency>
  1. 配置AWS S3相关的信息
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;import javax.annotation.PostConstruct;
import java.net.URI;
import java.time.Duration;/*** @CreateTime: 2024/05/31  18:17* @Description: S3配置文件* @Version: 1.0*/
@Component
public class S3Config {@Value("${spring.s3_config.bucket_name}")private String bucketName;@Value("${spring.s3_config.endpoint}")private String s3Endpoint;@Value("${spring.s3_config.aws_access_key_id}")private String awsAccessKeyId;@Value("${spring.s3_config.aws_secret_access_key}")private String awsSecretAccessKey;private S3Client s3Client;@PostConstructpublic void init() {// 将凭证作为类级别的静态变量,避免每次调用都创建AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(awsAccessKeyId, awsSecretAccessKey);s3Client = S3Client.builder().region(Region.US_EAST_1)  // 选择正确的区域.endpointOverride(URI.create(s3Endpoint))// s3 服务器端点地址.credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).overrideConfiguration(ClientOverrideConfiguration.builder().apiCallTimeout(Duration.ofMinutes(10))  // 设置整个请求的最大超时为 10 分钟.apiCallAttemptTimeout(Duration.ofMinutes(9))  // 每次尝试的最大超时为 9 分钟.build()).build();}/***  获取桶名*/public String getBucketName() {return bucketName;}/***  获取亚马逊s3客户端*/public S3Client getS3Client() {return s3Client;}
}
  1. 生成 S3 预览链接
	/*** @description: 生成 S3 预览链接* @param realPath 生成 S3 预览链接的真实地址* @return 如果成功生成预览链接则返回链接字符串,否则返回 null*/public static String generatePreviewUrl(String realPath) {try {// 创建 S3Presigner 实例private static final S3Presigner presigner = S3Presigner.builder().region(Region.US_EAST_1) // 选择正确的区域.credentialsProvider(StaticCredentialsProvider.create(awsCredentials)).build();// 获取文件扩展名并根据扩展名获取内容类型String extension = realPath.substring(realPath.lastIndexOf(".") + 1);String contentType = FileEnum.getByExtension(extension).getContentType();// 构建 GetObjectRequest 对象GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName).key(realPath).responseContentType(contentType) // 设置响应内容类型.build();// 构建 GetObjectPresignRequest 对象GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder().signatureDuration(Duration.ofDays(7)) // 设置预签名 URL 的有效期.getObjectRequest(getObjectRequest).build();// 生成预签名的 URLreturn presigner.presignGetObject(getObjectPresignRequest).url().toString();} catch (Exception e) {// 捕获并打印任何异常log.error("生成预览链接失败: " + e);throw new RuntimeException("生成预览链接失败");}}
  1. 上传文件到S3
 	/*** @description: 上传文件到S3* @param file 上传的文件* @return 如果成功上传返回 true,否则返回 false*/public static String uploadFile(MultipartFile file) {try {// 获取上传的文件String fileName = file.getOriginalFilename();// 参数验证:确保文件名不为空if (fileName == null || fileName.isEmpty()) {throw new ServiceException("文件名无效");}String path = projectPath + fileName;  // 在S3存储桶中存储的路径// 获取文件输入流try (InputStream fileStream = file.getInputStream()) {// 创建 PutObjectRequestPutObjectRequest putObjectRequest = PutObjectRequest.builder().bucket(bucketName).key(path)  // 设置 S3 存储对象的路径.build();// 上传文件到 S3PutObjectResponse putObjectResponse = s3Client.putObject(putObjectRequest,RequestBody.fromInputStream(fileStream, file.getSize()));// 返回上传文件的路径return path;} catch (Exception e) {log.error("上传文件失败: " + e);throw new RuntimeException("上传文件失败");}}
  1. 删除 S3 文件
  	/*** @description: 删除 S3 文件* @param fileUrl 要删除的文件的 URL 或对象名称*/public static void removeFile(String realPath) {try {// 创建删除文件的请求对象DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder().bucket(bucketName)  // 存储桶名称.key(realPath)        // 文件路径.build();// 执行文件删除操作s3Client.deleteObject(deleteObjectRequest);} catch (Exception e) {log.error("文件删除失败: " + e);throw new RuntimeException("文件删除失败");}}
  1. 从s3获取文件流
/*** @description: 通过realPath获取文件流* @param: realPath* @return: InputStream **/public static InputStream downloadByS3Url(String realPath) throws IOException {try {// 创建 GetObjectRequest 请求,指定存储桶名称和对象键GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName)        // S3 存储桶名称.key(realPath)            // S3 对象键.build();// 获取对象并返回文件的输入流InputStream fis = s3Client.getObject(getObjectRequest); // 获取文件输入流return fis;} catch (Exception e) {log.error("获取文件流失败: " + e);throw new RuntimeException("获取文件流失败");}}
  1. 从s3下载文件
/*** @description: 从 S3 下载文件* @param filePath 要下载的文件路径* @param downloadPath 本地存储路径*/public static void downloadFile(String filePath, String downloadPath) {try {// 创建 GetObjectRequest 请求GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName)  // 存储桶名称.key(filePath)        // S3 中的文件路径.build();// 执行下载操作并获取文件响应GetObjectResponse getObjectResponse = s3Client.getObject(getObjectRequest,Paths.get(downloadPath));  // 下载到指定路径// 处理下载后的响应,如果需要可以做进一步处理System.out.println("文件已下载: " + getObjectResponse);} catch (S3Exception e) {// 捕获 AWS S3 异常并记录错误log.error("文件下载失败: " + e.awsErrorDetails().errorMessage());throw new RuntimeException("文件下载失败");} catch (Exception e) {// 捕获其他异常log.error("文件下载失败: " + e);throw new RuntimeException("文件下载失败");}}

三、总结

MinIO 客户端:

  • 适用于本地部署的 S3 兼容存储,或者想要避免依赖 AWS 提供的 SDK。通过 MinIO,你可以在 S3 和 MinIO 之间无缝迁移,或用于私有云环境。

AWS SDK:

  • 适用于直接操作 AWS S3 服务,提供更多 AWS 的特性和功能支持。如果你的应用已经在 AWS 云上运行,使用 AWS SDK 是更理想的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity中的数学应用 之 插值函数处理角色朝向 (初中难度 +Matlab)

CodeMonkey教程&#xff1a; https://www.youtube.com/watch?vQDWlGOocKm8 Siki学院汉化教程&#xff1a;如何使用Unity开发分手厨房&#xff08;胡闹厨房&#xff09;-Unity2023 - SiKi学院|SiKi学堂 - unity|u3d|虚幻|ue4/5|java|python|人工智能|视频教程|在线课程 版本&am…

专业解析 .bashrc 中 ROS 工作空间的加载顺序及其影响 ubuntu 机器人

专业解析 .bashrc 中 ROS 工作空间的加载顺序及其影响 在使用 ROS&#xff08;Robot Operating System&#xff09;进行开发时&#xff0c;通常会涉及多个 Catkin 工作空间&#xff08;Catkin Workspace&#xff09;。这些工作空间包含不同的 ROS 包和节点&#xff0c;可能相互…

第三方Cookie的消亡与Google服务器端标记的崛起

随着互联网用户对隐私保护的关注日益增强&#xff0c;各大浏览器正在逐步淘汰第三方Cookie。这一变革深刻影响了广告商和数字营销人员的用户跟踪和数据分析方式。然而&#xff0c;Google推出的服务器端标记技术为这一挑战提供了新的解决方案。 什么是第三方Cookie&#xff1f; …

SQL注入利用方式(实战Hack World 1)

一、布尔盲注利用 假如注入的网页能返回1或0的提示信息&#xff0c;我们可以写如下代码: select password from admin where username 1 or 11;#11是我们利用的逻辑点&#xff0c;我们能在此处进行一个判断&#xff0c;比如判断某个数据字段第几位上的字符是否为’ 1’&#…

nlp培训重点

SGD梯度下降公式&#xff1a; 当梯度大于0时&#xff0c;变小&#xff0c;往左边找梯度接近0的值。 当梯度小于0时&#xff0c;减去一个负数会变大&#xff0c;往右边找梯度接近0的值&#xff0c;此时梯度从负数到0上升 #coding:utf8import torch import torch.nn as nn impo…

Qt5语法的connect指定多个重载信号槽函数中的具体某一个

Qt5新语法的connect函数&#xff0c;使用起来更加简洁明了&#xff0c;但如果信号槽有同名的多个重载函数&#xff0c;只用类名和函数名就无法绑定&#xff0c;这时&#xff0c;可以使用qOverload来指定参数类型&#xff0c;例如&#xff1a; connect(ui->comboBox, qOverlo…

如何在Spark中使用gbdt模型分布式预测

这目录 1 训练gbdt模型2 第三方包python环境打包3 Spark中使用gbdt模型3.1 spark配置文件3.2 主函数main.py 4 spark任务提交 1 训练gbdt模型 我们可以基于lightgbm快速的训练一个gbdt模型&#xff0c;训练相对比较简单&#xff0c;只要把训练样本处理好&#xff0c;几行代码可…

38 基于单片机的宠物喂食(ESP8266、红外、电机)

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于STC89C52单片机&#xff0c;采用L298N驱动连接P2.3和P2.4口进行电机驱动&#xff0c; 然后串口连接P3.0和P3.1模拟ESP8266&#xff0c; 红外传感器连接ADC0832数模转换器连接单片机的P1.0~P1.…

Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo)

Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo) 目录 Python 【图像分类】之 PyTorch 进行猫狗分类功能的实现(Swanlab训练可视化/ Gradio 实现猫狗分类 Demo) 一、简单介绍 二、PyTorch 三、CNN 1、神经网络 2、卷…

HTML5系列(7)-- Web Storage 实战指南

前端技术探索系列&#xff1a;HTML5 Web Storage 实战指南 &#x1f5c4;️ 致读者&#xff1a;本地存储的新纪元 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 HTML5 中的 Web Storage 技术&#xff0c;这是一个强大的本地存储解决方案&#xff0c;让我们能…

week 6 - SQL Select II

Overview 1. Joins 包括交叉连接&#xff08;Cross&#xff09;、内连接&#xff08;Inner&#xff09;、自然连接&#xff08;Natural&#xff09;、外连接&#xff08;Outer&#xff09; 2. ORDER BY to produce ordered output 3. 聚合函数&#xff08;Aggregate Functio…

算法训练营day23(二叉树09:修建二叉搜索树,有序数组转化为平衡二叉搜索树,二叉搜索树转化为累加树,二叉树专题总结)

第六章 二叉树part09今日内容&#xff1a;● 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树 ● 总结篇 详细布置 669. 修剪二叉搜索树 这道题目比较难&#xff0c;比 添加增加和删除节点难的多&#xff0c;建议先看视频理解。题目…

C语言操作符深度解析

目录 一、操作符的分类 1、算术操作符 1、1、 和- 1、2、* 1、3、/ 1、4、% 2、赋值操作符&#xff1a;和复合赋值 2、1、连续赋值 2、2、复合赋值符 3、单⽬操作符&#xff1a;、--、、- 3、1、和-- 3、1、1、前置 3、1、2、后置 3、2、1、前置-- 3、2、2、后…

打造高质量技术文档的关键要素(结合MATLAB)

在技术的浩瀚海洋中&#xff0c;一份优秀的技术文档宛如精准的航海图。它不仅是知识传承的载体&#xff0c;也是团队协作的桥梁&#xff0c;更是产品成功的幕后英雄。打造出色的技术文档并非易事&#xff0c;以下将从多个方向探讨如何做到这一点。 文章目录 方向一&#xff1a;…

《C++与人工智能:照亮能源可持续发展之路》

在全球对能源需求持续攀升以及对可持续发展日益重视的当下&#xff0c;如何有效解决能源领域的复杂问题成为了亟待攻克的关键挑战。而 C与人工智能技术的融合&#xff0c;正犹如一盏明灯&#xff0c;为能源管理、可再生能源预测等方面开辟出全新的路径&#xff0c;有力地推动着…

Python 深度学习框架之Keras库详解

文章目录 Python 深度学习框架之Keras库详解一、引言二、Keras的特点和优势1、用户友好2、多网络支持3、跨平台运行 三、Keras的安装和环境配置1、软硬件环境2、Python虚拟环境 四、使用示例1、MNIST手写数字识别 五、总结 Python 深度学习框架之Keras库详解 一、引言 Keras是…

【大语言模型】ACL2024论文-23 检索增强的多语言知识编辑

【大语言模型】ACL2024论文-23 检索增强的多语言知识编辑 目录 文章目录 【大语言模型】ACL2024论文-23 检索增强的多语言知识编辑目录摘要研究背景问题与挑战如何解决核心创新点算法模型实验效果&#xff08;包含重要数据与结论&#xff09;相关工作后续优化方向 后记 检索增强…

android user版本默认usb模式为充电模式

android插入usb时会切换至默认设置的模式&#xff0c;debug版本为adb&#xff0c;user版本为mtp protected long getChargingFunctions() {// if ADB is enabled, reset functions to ADB// else enable MTP as usual.if (isAdbEnabled()) {return UsbManager.FUNCTION_ADB;} e…

_C#_串口助手_字符串拼接缺失问题(未知原理)

最近使用WPF开发串口助手时&#xff0c;遇到一个很奇怪的问题&#xff0c;无论是主线程、异步还是多线程&#xff0c;当串口接收速度达到0.016s一次以上&#xff0c;就会发生字符串缺失问题并且很卡。而0.016s就一切如常&#xff0c;仿佛0.015s与0.016s是天堑之隔。 同一份代码…

CF Round988 题解报告

/***实力还是要努力 D 赛时我过了&#xff0c;就不讲了&#xff0c;毕竟我过的也大概是简单题&#xff1b; 代码&#xff1a; #include<iostream> #include<queue> using namespace std; #define int long long int t; int n,m,l; struct hurdle{int l,r,len; …