大家好!我是sum墨,一个一线的底层码农,平时喜欢研究和思考一些技术相关的问题并整理成文,限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

以下是正文!

对象存储是什么?

对象存储是一种数据存储方式,它将数据分割成不同的对象,并为每个对象分配一个唯一的标识符,用于访问和操作数据。这些对象被存储在多个服务器上,以确保数据的可靠性和可用性。对象存储适合存储大量数据,具有可扩展性、低成本和高安全性等特点。

这段话太专业了,以至于有点让人看不懂。私以为对象存储就是『分布式文件存储系统』,可能是我们只会用它来存储图片、视频、文档等文件吧,然后数据库(比如MySQL)只存储文件的访问链接。目前接触的对象存储有

阿里云对象存储OSS、天翼云对象存储融合版、自建对象存储MinIO。

  • 阿里云对象存储OSS

帮助文档链接

  • 天翼云对象存储融合版

帮助文档链接

  • MinIO对象存储

帮助文档链接

这三款对象存储产品对比如下

产品 功能特点 是否收费 是否开源 对接难易度
阿里云对象存储OSS 阿里云OSS提供了丰富的存储、数据处理和分发功能,可以满足各种场景的需求 收费 不开源 只需要ak/sk,然后看文档即可
天翼云对象存储融合版 天翼云对象存储融合版主要面向移动互联网应用,提供了数据管理、在线处理等功能 收费 不开源 只需要ak/sk,然后看文档即可
MinIO对象存储 MinIO专注于提供高性能、高可用的对象存储服务。 免费 开源 只需要ak/sk,然后看文档即可

总之有钱的话就买服务,没钱就自己搭,总有合适自己的。

对象存储和数据库的区别

各维度对比

存储 数据结构 数据处理 存储方式 可伸缩性
数据库存储 数据库是基于表格的存储方式,每个表格有特定的列和行。 数据库主要用于存储结构化数据,如文本、数字和日期等。数据库可以进行更复杂的数据处理,如查询、过滤和排序等。 数据库通常使用关系型数据库或NoSQL数据库等 数据库在扩展性上需要更多的运维和管理
对象存储 对象存储是基于对象的存储方式,每个对象可以是任何类型的文件 对象存储通常用于存储大量非结构化数据,如图片、视频和音频等 对象存储通常使用分布式存储技术将数据分散存储在不同的节点上 对象存储具有良好的扩展性,因此可以轻松地添加新的节点来处理更多的数据

项目对接流程图对比

CRUD之阿里云对象存储

1. 安装Java SDK

一般都是通过maven直接引入

<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>

2. 获取Client

官方获取Client代码示例

// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret"; // 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret); // 关闭OSSClient。
ossClient.shutdown();

我一般会将其变成一个Component

@Component
public class AliyunOssClient { @Value("${oss.endpoint}")
private String endpoint;
@Value("${aliyun.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.accessKeySecret}")
private String accessKeySecret; @Bean(name = "aliyunOssClient")
public OSS aliyunOssClient() {
// 构建并返回OSSClient
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
}

3. 增删改查操作

(1)对象公共读&上传和访问

官方文档

 /**
* 简单上传-流式上传-公共读
*
* @param bucketName bucket名称
* @param key 文件名
* @param inputStream 输入流
* @return PutObjectResult 上传结果
*/
public static PutObjectResult putObjectByInputStreamAndPublicRead(String bucketName, String key,
InputStream inputStream) {
ObjectMetadata metadata = new ObjectMetadata();
//设置StorageClass为Standard即为
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//设置读写为公共读写
metadata.setObjectAcl(CannedAccessControlList.PublicRead);
// 准备OSS上传对象请求
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream);
putObjectRequest.setMetadata(metadata);
// 上传
return ossClient.putObject(putObjectRequest);
}

当设置文件的访问权限为公共读时,直接拼接文件的访问链接就可以了,比如endpoint为oss-cn-hangzhou.aliyuncs.com,bucket为file-bucket,key为/test/file/1.png

那么访问链接就为:https://file-bucket.oss-cn-hangzhou.aliyuncs.com/test/file/1.png

(2)对象私有读&上传和访问

官方文档

 /**
* 简单上传-流式上传-私有读写
*
* @param bucketName bucket名称
* @param key 文件名
* @param inputStream 输入流
* @return PutObjectResult 上传结果
*/
public static PutObjectResult putObjectByInputStreamAndPrivate(String bucketName, String key,
InputStream inputStream) {
ObjectMetadata metadata = new ObjectMetadata();
//设置StorageClass为Standard即为
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
//设置读写为公共读写
metadata.setObjectAcl(CannedAccessControlList.Private);
// 准备OSS上传对象请求
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream);
putObjectRequest.setMetadata(metadata);
// 上传
return ossClient.putObject(putObjectRequest);
}

当设置文件的访问权限为私有读时,直接拼接访问链接是没法访问该文件的,访问会报如下错误:

<Error>
<Code>AccessDenied</Code>
<Message>You do not have read permission on this object.</Message>
<RequestId>6488223453BCC63831BB3EC4</RequestId>
<HostId>file-bucket.oss-cn-hangzhou.aliyuncs.com</HostId>
<EC>0003-00000005</EC>
</Error>

这时就需要对key进行加签操作了,加签代码如下:

 /**
* 通过bucketName、key、过期时间生成文件访问链接(时效性)
*
* @param bucketName bucket名称
* @param key 文件名
* @param expiration 过期时间
* @return 文件访问链接
*/
public static String getSignObjectUrl(String bucketName, String key, Date expiration) {
return ossClient.generatePresignedUrl(bucketName, key, expiration).toString();
}

那么获取的链接格式就是这样了:https://file-bucket.oss-cn-hangzhou.aliyuncs.com/test/file/test.png?Expires=xxx&OSSAccessKeyId=xxxx&Signature=xxxx

(3)对象下载

官方文档

下载到文件

   /**
* 通过bucketName、key、文件路径 下载OSS文件到本地文件
*
* @param bucketName bucket名称
* @param key 文件名
* @param pathName 本地文件路径
*/
public static void getObjectToFile(String bucketName, String key, String pathName) {
// 下载OSS文件到本地
ossClient.getObject(new GetObjectRequest(bucketName, key), new File(pathName));
}

流式下载

 /**
* 通过bucketName、key 下载OSS变成字节流
*
* @param bucketName bucket名称
* @param key 文件名
*/
public static void getObjectToStream(String bucketName, String key) {
OSSObject ossObject = null;
BufferedReader reader = null;
try {
ossObject = ossClient.getObject(bucketName, key);
reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
while (true) {
String line = null;
line = reader.readLine();
if (line == null) { break; } System.out.println("\n" + line);
}
} catch (IOException e) {
log.error("下载oss文件异常", e);
} finally {
try {
// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
reader.close();
// ossObject对象使用完毕后必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
ossObject.close();
} catch (IOException e) {
log.error("关闭流发生异常", e);
}
}
}

(4)对象删除

官方文档

   /**
* 通过bucketName、key删除文件
*
* @param bucketName bucket名称
* @param key 文件名
*/
public static void delObject(String bucketName, String key) {
// 删除文件或目录。如果要删除目录,目录必须为空。
ossClient.deleteObject(bucketName, key);
}

(5)图片处理

官方文档

这个接口目前只有阿里云有写文档,其他云都是一笔带过没有详细说明,作用是将上传到OSS的原始图片进行缩放、旋转、加水印等操作,非常好用,在此强烈安利一波!!!

  • 将图片缩放为固定宽高100 px
// 将图片缩放为固定宽高100 px。
String style = "image/resize,m_fixed,w_100,h_100";
GetObjectRequest request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
// 将处理后的图片命名为example-resize.jpg并保存到本地。
// 填写本地文件的完整路径,例如D:\\localpath\\example-resize.jpg。如果指定的本地文件存在会覆盖,不存在则新建。
// 如果未指定本地路径只填写了本地文件名称(例如example-resize.jpg),则文件默认保存到示例程序所属项目对应本地路径中。
ossClient.getObject(request, new File("D:\\localpath\\example-resize.jpg"));
  • 从坐标(100,100)开始,将图片裁剪为宽高100 px
// 从坐标(100,100)开始,将图片裁剪为宽高100 px。
style = "image/crop,w_100,h_100,x_100,y_100";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
// 将处理后的图片命名为example-crop.jpg并保存到本地。
ossClient.getObject(request, new File("D:\\localpath\\example-crop.jpg"));
  • 将图片旋转90°
 // 将图片旋转90°。
style = "image/rotate,90";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
// 将处理后的图片命名为example-rotate.jpg并保存到本地。
ossClient.getObject(request, new File("D:\\localpath\\example-rotate.jpg"));
  • 在图片中添加文字水印。
// 在图片中添加文字水印。
// 文字水印的文字内容经过Base64编码后,再将编码结果中的加号(+)替换成短划线(-),正斜线(/)替换成下划线(_)并去掉尾部的等号(=),从而得到水印字符串。
// 指定文字水印的文字内容为Hello World,文字内容进行编码处理后得到的水印字符串为SGVsbG8gV29ybGQ。
style = "image/watermark,text_SGVsbG8gV29ybGQ";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
// 将处理后的图片命名为example-watermarktext.jpg并保存到本地。
ossClient.getObject(request, new File("D:\\localpath\\example-watermarktext.jpg"));
  • 在图片中添加图片水印。请确保水印图片已保存在图片所在Bucket中
// 在图片中添加图片水印。请确保水印图片已保存在图片所在Bucket中。
// 水印图片的完整路径经过Base64编码后,再将编码结果中的加号(+)替换成短划线(-),正斜线(/)替换成下划线(_)并去掉尾部的等号(=),从而得到水印字符串。
// 指定水印图片的完整路径为panda.jpg,完整路径进行编码处理后得到的水印字符串为cGFuZGEuanBn。
style = "image/watermark,image_cGFuZGEuanBn";
request = new GetObjectRequest(bucketName, objectName);
request.setProcess(style);
// 将处理后的图片命名为example-watermarkimage.jpg并保存到本地。
ossClient.getObject(request, new File("D:\\localpath\\example-watermarkimage.jpg"));

除了这些之外还有很多其他的功能,大家可以自己看文档~

顺便说一个我们使用的案例

我们之前在开发项目的时候,做了个文章发布的功能,简单来说就是PC后台管理端发布文章,然后在微信小程序、H5小程序点击查看。文章的内容是包括图文的,有些文章图片上传的是原图,一张好几兆大小,用户在手机端查看文章时加载慢不说,那流量更是跑得飞起。我们就是用这个功能对图片进行等比例缩放,控制图片大小来解决的。

当时我们使用富文本框写的文章,这种文章会把图片、文字和dom元素混在一起,而且每张图片大小、分辨率都不同,这种情况下后端是没法对图片进行处理的,能处理图片的只有前端。为了解决这个问题,阿里云OSS提供了一个参数:x-oss-process。具体效果,我们直接看对比图:

从上图看,加了参数后,图片直接变小,但也模糊了。也就是说,图片根本不需要后端处理,前端自己拼接参数就可以处理图片了,非常的方便,而且原图链接也在前端,还可以做长按查看原图功能。

CRUD之天翼云对象存储

1. 安装Java SDK

同样都是通过maven直接引入,但是多了好几个依赖,毕竟不是自研的。

<!-- 天翼云 -->
<dependency>
<groupId>cn.chinatelecom</groupId>
<artifactId>oss-java-sdk</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.336</version>
</dependency>
<!-- 使用sts服务需要添加以下依赖 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sts</artifactId>
<version>1.11.336</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.3</version>
</dependency>

2. 获取Client

我还是将其变成一个Component

@Component
public class TianyiyunOssClient { @Value("${oss.endpoint}")
private String endpoint;
@Value("${tianyiyun.accessKeyId}")
private String accessKeyId;
@Value("${tianyiyun.accessKeySecret}")
private String accessKeySecret; @Bean
public AmazonS3 getOssClient() {
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKeyId, accessKeySecret);
ClientConfiguration clientConfiguration = new ClientConfiguration();
EndpointConfiguration endpointConfiguration = new EndpointConfiguration(
endpoint, Regions.DEFAULT_REGION.getName());
return AmazonS3ClientBuilder.standard()
//客户端设置
.withClientConfiguration(clientConfiguration)
//凭证设置
.withCredentials(new AWSStaticCredentialsProvider(credentials))
//endpoint设置
.withEndpointConfiguration(endpointConfiguration)
.build();
}
}

3. 增删改查操作

(1)上传对象

官方文档

    /**
* 简单上传-流式上传-公共读
*
* @param bucketName bucket名称
* @param key 文件名
* @param inputStream 输入流
* @return PutObjectResult 上传结果
*/
public static PutObjectResult putObjectByInputStream(String bucketName, String key, InputStream inputStream) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// 准备OSS上传对象请求
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, metadata);
putObjectRequest.setMetadata(metadata);
//设置上传对象的Acl为公共读,私有写
putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead);
// 上传
return tianyiyunOssClient.putObject(putObjectRequest);
}

基本和阿里云一模一样,这里就不赘述怎么实现公共读和私有读了,核心就是设置setCannedAcl。

(2)获取对象访问链接

官方文档


/**
* 生成预签名下载链接
*
* @param bucketName bucket名称
* @param key 文件名
* @param expiration 过期时间
* @return 文件访问链接
*/
public static String getObjectUrl(String bucketName, String key, Date expiration) {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key)
.withMethod(HttpMethod.GET)
.withExpiration(expiration);
return tianyiyunOssClient.generatePresignedUrl(request).toString();
}

这里稍微和阿里云不太一样,虽然GeneratePresignedUrlRequest也有setExpiration方法,但好像不生效,必须要使用上面这种形式才可以加签,奇怪。

(3)删除对象

官方文档

/**
* 通过bucketName、key删除文件
*
* @param bucketName bucket名称
* @param key 文件名
*/
public static void delObject(String bucketName, String key) {
// 删除文件或目录。如果要删除目录,目录必须为空。
tianyiyunOssClient.deleteObject(bucketName, key);
}

(4)图片处理

官方文档

这里天翼云的文档没有详细说明,但我还是找到了天翼云对象存储是怎么处理图片的。同阿里云的x-oss-process,天翼云的处理参数为x-amz-process。用法也和阿里云的一样,直接把参数拼接在url后面即可。

try {
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectKey)
.withMethod(HttpMethod.GET)
.withExpiration(expiration);
// 在URL中添加额外参数
request.addRequestParameter("x-amz-limit", String.format("rate=%d", 100));
request.addRequestParameter("x-amz-process", "image/watermark,text_12345678");
URL url = s3.generatePresignedUrl(request);
} catch (AmazonServiceException e) {
System.err.println(e.getErrorMessage());
}

CRUD之MinIO对象存储

1. 安装Java SDK

同上

     <dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.4.5</version>
</dependency>

2. 获取Client

同上,注册为Component

@Component
public class MinioOssClient { @Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey; /**
* 注入minio 客户端
*
* @return 客户端
*/
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.httpClient(getUnsafeOkHttpClient())
.build();
} private OkHttpClient getUnsafeOkHttpClient() {
try {
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws
CertificateException {
} @Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
throws CertificateException {
} @Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
}; X509TrustManager x509TrustManager = (X509TrustManager)trustAllCerts[0];
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, x509TrustManager); builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
return builder.build(); } catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
} }

这里多了一个方法getUnsafeOkHttpClient方法,原因是MinIO是我们自建的,使用的https://ip:port的方式去调用,而不是域名方式。对接过这种地址的小伙伴都知道,如果不处理一下https的安全证书,调用的时候就会报错。该方法是为了解决SSL证书验证异常,即当请求的URL使用的是HTTPS协议时,如果证书无效或不被信任,会抛出SSLHandshakeException异常,通过自定义TrustManager和SSLSocketFactory来实现忽略证书的验证,从而避免SSL异常。

3. 增删改查操作

(1)上传对象

 /**
* 简单上传-流式上传
*
* @param bucketName bucket名称
* @param key 文件名
* @param inputStream 输入流
* @return ObjectWriteResponse 上传结果
*/
public static ObjectWriteResponse uploadInputStream(String bucketName, String key, InputStream inputStream)
throws Exception {
//设置权限
Map<String, String> userMetadata = new HashMap<>();
//设置为公有读
userMetadata.put("access-control", "public-read");
//设置为私有读
// userMetadata.put("access-control", "private");
// 准备OSS上传对象请求
PutObjectArgs putObjectArgs = PutObjectArgs.builder()
// bucketName
.bucket(bucketName)
// 文件名称
.object(key)
//设置文件权限
.userMetadata(userMetadata)
.stream(inputStream, inputStream.available(), -1)
.build();
// 上传文件
return minioClient.putObject(putObjectArgs);
}

(2)获取对象访问链接

  /**
* 获取文件地址
*
* @param bucketName bucketName
* @param key 文件名称
* @param duration 过期时长
* @param unit 过期时长单位
* @return 文件地址
*/
public static String getObjectUrl(String bucketName, String fileName, int duration, TimeUnit unit)
throws Exception {
// 查看文件地址
return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
// bucketName
.bucket(bucketName)
// 文件名称
.object(fileName)
// 过期参数
.expiry(duration, unit)
// 请求方式
.method(Method.GET)
// 构建参数
.build()
);
}

(3)删除对象

    /**
* 通过bucketName、key删除文件
*
* @param bucketName bucket名称
* @param key 文件名
*/
public static void delObject(String bucketName, String key) throws Exception {
minioClient.removeObject(
RemoveObjectArgs.builder()
.bucket(bucketName)
.object(key)
.build());
}

(4)图片处理

很可惜,MinIO没有图片处理的功能。

总结一下

这三种对象存储工具都是我在真实项目中使用过的,它们的使用流程相似,接口名称也差不多,但是在一些细节上还是有些不同的地方。为了让大家更好地了解它们,我在文章中都有标明区别。阿里云和天翼云使用起来比较方便,只需要购买服务就可以了。而MinIO就比较麻烦,需要自己搭建一个服务器环境,并在生产环境中满足主备、证书等方面的要求,这也让我在使用过程中踩了不少坑。不过,我会在新的文章中详细介绍如何搭建MinIO服务器以及如何解决它的问题。

对象存储?CRUD Boy实现对文件的增删改查的更多相关文章

  1. MyBatis学习(二)、SQL语句映射文件(2)增删改查、参数、缓存

    二.SQL语句映射文件(2)增删改查.参数.缓存 2.2 select 一个select 元素非常简单.例如: <!-- 查询学生,根据id --> <select id=" ...

  2. MyBatis学习 之 二、SQL语句映射文件(2)增删改查、参数、缓存

    目录(?)[-] 二SQL语句映射文件2增删改查参数缓存 select insert updatedelete sql parameters 基本类型参数 Java实体类型参数 Map参数 多参数的实 ...

  3. java对xml文件做增删改查------摘录

    java对xml文件做增删改查 package com.wss; import java.io.File;import java.util.ArrayList;import java.util.Lis ...

  4. 基于SpringMVC的文件(增删改查)上传、下载、更新、删除

    一.项目背景 摘要:最近一直在忙着项目的事,3个项目过去了,发现有一个共同的业务,那就是附件的处理,附件包括各种文档,当然还有图片等特殊文件,由于时间的关系,每次都是匆匆忙忙的搞定上线,称这项目的空档 ...

  5. 【练习】Python第四次:实现对文件的增删改查

    一,实现对文件的增删改查 (一),三级菜单的处理结构及退出技巧:使用TAG标记 tag=True while tag: print('leve1') choice=input("level1 ...

  6. Python文件操作-文件的增删改查

    需求:对文件进行增删改查 由于时间原因,本次代码没有增加任何注释,如有疑问,请联系编辑者:闫龙 其实我也是醉了,看着这些个代码,我脑袋也特么大了,没办法,大神说了,不让用新知识,只可以使用学过的,所以 ...

  7. Python 模拟SQL对文件进行增删改查

    #!/usr/bin/env python # _*_ coding:UTF-8 _*_ # __auth__: Dalhhin # Python 3.5.2,Pycharm 2016.3.2 # 2 ...

  8. 使用dom4j对xml文件进行增删改查

    1.使用dom4j技术对dom_demo.xml进行增删改查 首选要下载dom4j的jar包 在官网上找不到,网上搜索了一下在这个链接:http://sourceforge.net/projects/ ...

  9. xml 文件的增删改查

    序列化和反序列化helper using System; using System.Collections.Generic; using System.Linq; using System.Text; ...

  10. 二、SQL语句映射文件(2)增删改查、参数、缓存

    //备注:该博客引自:http://limingnihao.iteye.com/blog/106076 2.2 select 一个select 元素非常简单.例如: Xml代码 收藏代码 <!- ...

随机推荐

  1. Linux中Python自动输入sudo 密码【管道 sudo参数 stdin&stdout】

    一.背景和需求 背景: 由于docker服务进程都是以root帐号的身份运行的,所以用docker跑abpred出来的文件所有者都是root, 而我作为一般用户,操作这个文件不够权限,运行代码时需要s ...

  2. 1688关键字搜索新品数据API接口(item_search_new-按关键字搜索新品数据)

    1688关键字搜索新品数据API接口(item_search_new-按关键字搜索新品数据)代码接口教程如下: 公共参数 名称 类型 必须 描述key String 是 调用key(必须以GET方式拼 ...

  3. c#快速入门~在java基础上,知道C#和JAVA 的不同即可

    观看下文前提:如果你的主语言是java,现在想再学一门新语言C#,下文是在java基础上,对比和java的不同,快速上手C# C# 学习参考文档和开发工具 微软c#官方文档:https://learn ...

  4. InnoDB引擎之flush脏页

    利用 WAL 技术,数据库将随机写转换成了顺序写,大大提升了数据库的性能,由此也带来了内存脏页的问题. 脏页会被后台线程自动 flush,也会由于数据页淘汰而触发 flush,而刷脏页的过程由于会占用 ...

  5. 电脑上跨平台的电子书阅读器Koodo Reader

    https://wbsu2003.gitee.io/2021/04/30/%E7%94%B5%E8%84%91%E4%B8%8A%E8%B7%A8%E5%B9%B3%E5%8F%B0%E7%9A%84 ...

  6. 【LeetCode动态规划#08】完全背包问题实战与分析(零钱兑换II)

    零钱兑换II 力扣题目链接(opens new window) 给定不同面额的硬币和一个总金额.写出函数来计算可以凑成总金额的硬币组合数.假设每一种面额的硬币有无限个. 示例 1: 输入: amoun ...

  7. CSS—相对单位rem

    一.概述 rem是一个相对长度单位,它的单位长度取决于根标签html的字体尺寸.rem即root em的意思,中文翻译为根em.浏览器的文本尺寸一般默认为16px,即默认情况下: 1rem = 16p ...

  8. Awesome GPT 来了!

    大家好!我是韩老师. GPT, ChatGPT, OpenAI, LLM(大语言模型)等等技术的出现与应用,改变了许多的行业和人. 长期来看,类 GPT 的技术会对整个世界有着持续的改变. 我们几乎每 ...

  9. JS逆向实战13——某市公共资源交易中心Cookie混淆加密

    "本文地址:https://www.cnblogs.com/zichliang/p/17346860.html 目标网站 aHR0cDovL2xkZ2d6eS5obmxvdWRpLmdvdi ...

  10. flink之Sink to MySQL和Redis

    前言 下面这篇文章是使用Flink的Sink 写出数据到Redis和MySQL Flink之Sink写入Redis和MySQL Flink需要添加Sink的时候,需要自己去添加写Sink,我们可以实现 ...