66、Flink 的 DataStream Connectors 支持的 Formats 详解

支持的 Formats
1.概述

Format 定义如何对 Record 进行编码以进行存储,目前支持以下格式:

Avro
Azure Table
Hadoop
Parquet
Text files
2.Avro format

Flink 内置支持 Apache Avro 格式,Flink 的序列化框架可以处理基于 Avro schemas 生成的类,为了能够使用 Avro format,需要添加如下依赖到项目中。

<dependency><groupId>org.apache.flink</groupId><artifactId>flink-avro</artifactId><version>1.19.0</version>
</dependency>

如果读取 Avro 文件数据,必须指定 AvroInputFormat

示例

AvroInputFormat<User> users = new AvroInputFormat<User>(in, User.class);
DataStream<User> usersDS = env.createInput(users);

注意User 是一个通过 Avro schema 生成的 POJO 类,Flink 允许选择 POJO 中字符串类型的键。

usersDS.keyBy("name");

注意

  • 在 Flink 中可以使用 GenericData.Record 类型,但是不推荐使用;因为该类型的记录中包含了完整的 schema,导致数据非常密集,使用起来可能很慢;
  • Flink 的 POJO 字段选择也适用于从 Avro schema 生成的 POJO 类;但只有将字段类型正确写入生成的类时,才能使用;
  • 如果字段是 Object 类型,则不能将该字段用作 join 键或 grouping 键;
  • 在 Avro 中如 {"name": "type_double_test", "type": "double"}, 指定字段是可行的,但是如 ({"name": "type_double_test", "type": ["double"]},) 指定包含一个字段的复合类型就会生成 Object 类型的字段;
  • ({"name": "type_double_test", "type": ["null", "double"]},) 指定 nullable 类型字段也是可能产生 Object 类型的。
3.CSV format
a)概述

如果要使用 CSV 格式,需要在项目中添加如下依赖:

<dependency><groupId>org.apache.flink</groupId><artifactId>flink-csv</artifactId><version>1.19.0</version>
</dependency>

Flink 支持使用 CsvReaderFormat 读取CSV文件,读取器利用 Jackson 库,并允许传递 CSV schema 和解析配置。

CsvReaderFormat 初始化和使用示例如下

CsvReaderFormat<SomePojo> csvFormat = CsvReaderFormat.forPojo(SomePojo.class);
FileSource<SomePojo> source = FileSource.forRecordStreamFormat(csvFormat, Path.fromLocalFile(...)).build();

此时 CSV 解析的模式是使用 Jackson 库基于 SomePojo 类的字段自动派生的。

注意:需要将 @JsonPropertyOrder({field1,field2,...})注解添加到类定义中,使字段顺序与 CSV 文件列的字段顺序完全匹配。

b)高级配置

如果需要对 CSV schema 或解析配置进行更细粒度的控制,可以使用 CsvReaderFormat 的更低级的 forSchema 静态工厂方法:

CsvReaderFormat<T> forSchema(Supplier<CsvMapper> mapperFactory, Function<CsvMapper, CsvSchema> schemaGenerator, TypeInformation<T> typeInformation) 

以下是使用自定义列分隔符读取 POJO 的示例:

//必须匹配 CSV 文件中列的顺序
@JsonPropertyOrder({"city","lat","lng","country","iso2","adminName","capital","population"})
public static class CityPojo {public String city;public BigDecimal lat;public BigDecimal lng;public String country;public String iso2;public String adminName;public String capital;public long population;
}Function<CsvMapper, CsvSchema> schemaGenerator = mapper ->mapper.schemaFor(CityPojo.class).withoutQuoteChar().withColumnSeparator('|');CsvReaderFormat<CityPojo> csvFormat =CsvReaderFormat.forSchema(() -> new CsvMapper(), schemaGenerator, TypeInformation.of(CityPojo.class));FileSource<CityPojo> source =FileSource.forRecordStreamFormat(csvFormat, Path.fromLocalFile(...)).build();

相应的 CSV 文件:

Berlin|52.5167|13.3833|Germany|DE|Berlin|primary|3644826
San Francisco|37.7562|-122.443|United States|US|California||3592294
Beijing|39.905|116.3914|China|CN|Beijing|primary|19433000

还可以使用细粒度的 Jackson 设置读取更复杂的数据类型:

public static class ComplexPojo {private long id;private int[] array;
}CsvReaderFormat<ComplexPojo> csvFormat =CsvReaderFormat.forSchema(CsvSchema.builder().addColumn(new CsvSchema.Column(0, "id", CsvSchema.ColumnType.NUMBER)).addColumn(new CsvSchema.Column(4, "array", CsvSchema.ColumnType.ARRAY).withArrayElementSeparator("#")).build(),TypeInformation.of(ComplexPojo.class));

相应的 CSV 文件:

0,1#2#3
1,
2,1

与 TextLineInputFormat 类似,CsvReaderFormat 既可以用于流处理模式,也可以用于批处理模式。

4.Hadoop formats
a)项目配置

将以下依赖添加到 pom.xml 中使用 hadoop:

<dependency><groupId>org.apache.flink</groupId><artifactId>flink-hadoop-compatibility_2.12</artifactId><version>1.19.0</version>
</dependency>

如果想在本地运行 Flink 应用,需要将 hadoop-client 依赖也添加到 pom.xml

<dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.10.2</version><scope>provided</scope>
</dependency>
b)使用 Hadoop InputFormats

在 Flink 中使用 Hadoop InputFormats,首先必须使用 HadoopInputs 工具类的 readHadoopFilecreateHadoopInput 包装 Input Format;前者用于从 FileInputFormat 派生的 Input Format,而后者用于通用的 Input Format。

生成的 InputFormat 可通过使用 ExecutionEnvironment#createInput 创建数据源。

生成的 DataStream 包含 2 元组,其中第一个字段是 key,第二个字段是从 Hadoop InputFormat 接收的值。

示例:如何使用 Hadoop 的 TextInputFormat

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();KeyValueTextInputFormat textInputFormat = new KeyValueTextInputFormat();DataStream<Tuple2<Text, Text>> input = env.createInput(HadoopInputs.readHadoopFile(textInputFormat, Text.class, Text.class, textPath)
);
5.JSON
a)概述

需要添加如下依赖:

<dependency><groupId>org.apache.flink</groupId><artifactId>flink-json</artifactId><version>1.19.0</version><scope>provided</scope>
</dependency>

Flink 支持通过 JsonSerializationSchema/JsonDeserializationSchema 读取/写入 JSON 记录,它们使用 Jackson 库,并支持 Jackson 支持的任何类型,包括但不限于 POJO 和 ObjectNode。

JsonDeserializationSchema 可以与任何支持该 Deserialization Schema 的连接器一起使用。

示例:将其与 KafkaSource 一起使用以反序列化 POJO:

JsonDeserializationSchema<SomePojo> jsonFormat = new JsonDeserializationSchema<>(SomePojo.class);
KafkaSource<SomePojo> source =KafkaSource.<SomePojo>builder().setValueOnlyDeserializer(jsonFormat)...

JsonSerializationSchema 可以与任何支持 SerializationSchema 的连接器一起使用。

示例:将其与 KafkaSink 一起使用来序列化POJO:

JsonSerializationSchema<SomePojo> jsonFormat = new JsonSerializationSchema<>();
KafkaSink<SomePojo> source =KafkaSink.<SomePojo>builder().setRecordSerializer(new KafkaRecordSerializationSchemaBuilder<>().setValueSerializationSchema(jsonFormat)...
b)Custom Mapper

这两个架构都有接受 SerializableSupplier<ObjectMapper> 的构造函数,充当对象映射器的工厂。

使用此工厂,可以完全控制创建的映射器,并可以启用/禁用各种 Jackson 功能或注册模块,以扩展一组受支持的类型或添加其他功能。

JsonSerializationSchema<SomeClass> jsonFormat = new JsonSerializationSchema<>(() -> new ObjectMapper().enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)).registerModule(new ParameterNamesModule());
6.Parquet format
a)概述

Flink 支持读取 Parquet 文件并生成 Flink RowData 和 Avro 记录,使用 Parquet format,需要将 flink-parquet 依赖添加到项目中:

<dependency><groupId>org.apache.flink</groupId><artifactId>flink-parquet</artifactId><version>1.19.0</version>
</dependency>

要使用 Avro 格式,需要将 parquet-avro 依赖添加到项目中:

<dependency><groupId>org.apache.parquet</groupId><artifactId>parquet-avro</artifactId><version>1.12.2</version><optional>true</optional><exclusions><exclusion><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId></exclusion><exclusion><groupId>it.unimi.dsi</groupId><artifactId>fastutil</artifactId></exclusion></exclusions>
</dependency>

此格式与新的 Source 兼容,可以同时在批和流模式下使用。

  • 有界数据:列出所有文件并全部读取;
  • 无界数据:监控目录中出现的新文件。

当开启一个 File Source,会被默认为有界读取;如果想在连续读取模式下使用 File Source,必须额外调用 AbstractFileSource.AbstractFileSourceBuilder.monitorContinuously(Duration)

Vectorized reader

// Parquet rows are decoded in batches
FileSource.forBulkFileFormat(BulkFormat,Path...)// Monitor the Paths to read data as unbounded data
FileSource.forBulkFileFormat(BulkFormat,Path...)
.monitorContinuously(Duration.ofMillis(5L))
.build();

Avro Parquet reader

// Parquet rows are decoded in batches
FileSource.forRecordStreamFormat(StreamFormat,Path...)// Monitor the Paths to read data as unbounded data
FileSource.forRecordStreamFormat(StreamFormat,Path...).monitorContinuously(Duration.ofMillis(5L)).build();

下面的案例都是基于有界数据的。 如果想在连续读取模式下使用 File Source,必须额外调用 AbstractFileSource.AbstractFileSourceBuilder.monitorContinuously(Duration)

b)Flink RowData

在此示例中,将创建由 Parquet 格式的记录构成的 Flink RowDatas DataStream。

把 schema 信息映射为只读字段(“f7”、“f4” 和 “f99”),每个批次读取 500 条记录;

  • 第一个布尔类型的参数用来指定是否需要将时间戳列处理为 UTC。
  • 第二个布尔类型参数用来指定在进行 Parquet 字段映射时,是否要区分大小写。
  • 这里不需要水印策略,因为记录中不包含事件时间戳。
final LogicalType[] fieldTypes =new LogicalType[] {new DoubleType(), new IntType(), new VarCharType()};
final RowType rowType = RowType.of(fieldTypes, new String[] {"f7", "f4", "f99"});final ParquetColumnarRowInputFormat<FileSourceSplit> format =new ParquetColumnarRowInputFormat<>(new Configuration(),rowType,InternalTypeInfo.of(rowType),500,false,true);
final FileSource<RowData> source =FileSource.forBulkFileFormat(format,  /* Flink Path */).build();
final DataStream<RowData> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");
c)Avro Records

Flink 支持三种方式来读取 Parquet 文件并创建 Avro records (PyFlink 只支持 Generic record)

  • Generic record
  • Specific record
  • Reflect record

Generic record

使用 JSON 定义 Avro schemas,此示例使用了一个在 official Avro tutorial 中描述的示例相似的 Avro schema:

{"namespace": "example.avro","type": "record","name": "User","fields": [{"name": "name", "type": "string"},{"name": "favoriteNumber",  "type": ["int", "null"]},{"name": "favoriteColor", "type": ["string", "null"]}]
}

这个 schema 定义了一个具有三个属性的的 user 记录:name,favoriteNumber 和 favoriteColor。

在此示例中,将创建包含由 Avro Generic records 格式构成的 Parquet records 的 DataStream,Flink 会基于 JSON 字符串解析 Avro schema;也有很多其他的方式解析 schema,例如基于 java.io.File 或 java.io.InputStream。

然后可以通过 AvroParquetReaders 为 Avro Generic 记录创建 AvroParquetRecordFormat

// 解析 avro schema
final Schema schema =new Schema.Parser().parse("{\"type\": \"record\", "+ "\"name\": \"User\", "+ "\"fields\": [\n"+ "        {\"name\": \"name\", \"type\": \"string\" },\n"+ "        {\"name\": \"favoriteNumber\",  \"type\": [\"int\", \"null\"] },\n"+ "        {\"name\": \"favoriteColor\", \"type\": [\"string\", \"null\"] }\n"+ "    ]\n"+ "    }");final FileSource<GenericRecord> source =FileSource.forRecordStreamFormat(AvroParquetReaders.forGenericRecord(schema), /* Flink Path */).build();final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.enableCheckpointing(10L);final DataStream<GenericRecord> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");

Specific record

基于之前定义的 schema,可以通过利用 Avro 代码生成来生成类;一旦生成了类,就不需要在程序中直接使用 schema。

可以使用 avro-tools.jar 手动生成代码,也可以直接使用 Avro Maven 插件对配置的源目录中的任何 .avsc 文件执行代码生成。

此示例使用了样例 schema testdata.avsc :

[{"namespace": "org.apache.flink.formats.parquet.generated","type": "record","name": "Address","fields": [{"name": "num", "type": "int"},{"name": "street", "type": "string"},{"name": "city", "type": "string"},{"name": "state", "type": "string"},{"name": "zip", "type": "string"}]}
]

可以使用 Avro Maven plugin 生成 Address Java 类。

@org.apache.avro.specific.AvroGenerated
public class Address extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {// 生成的代码...
}

可以通过 AvroParquetReaders 为 Avro Specific 记录创建 AvroParquetRecordFormat, 然后创建一个包含由 Avro Specific records 格式构成的 Parquet records 的 DateStream。

final FileSource<GenericRecord> source =FileSource.forRecordStreamFormat(AvroParquetReaders.forSpecificRecord(Address.class), /* Flink Path */).build();final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.enableCheckpointing(10L);final DataStream<GenericRecord> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");

Reflect record

除了需要预定义 Avro Generic 和 Specific 记录, Flink 还支持基于现有 Java POJO 类从 Parquet 文件创建 DateStream。

在这种场景中,Avro 会使用 Java 反射为这些 POJO 类生成 schema 和协议。

本例使用了一个简单的 Java POJO 类 Datum :

public class Datum implements Serializable {public String a;public int b;public Datum() {}public Datum(String a, int b) {this.a = a;this.b = b;}@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) {return false;}Datum datum = (Datum) o;return b == datum.b && (a != null ? a.equals(datum.a) : datum.a == null);}@Overridepublic int hashCode() {int result = a != null ? a.hashCode() : 0;result = 31 * result + b;return result;}
}

可以通过 AvroParquetReaders 为 Avro Reflect 记录创建一个 AvroParquetRecordFormat, 然后创建一个包含由 Avro Reflect records 格式构成的 Parquet records 的 DateStream。

final FileSource<GenericRecord> source =FileSource.forRecordStreamFormat(AvroParquetReaders.forReflectRecord(Datum.class), /* Flink Path */).build();final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.enableCheckpointing(10L);final DataStream<GenericRecord> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");
d)使用 Parquet files 必备条件

为了支持读取 Avro Reflect 数据,Parquet 文件必须包含特定的 meta 信息。为了生成 Parquet 数据,Avro schema 信息中必须包含 namespace, 以便让程序在反射执行过程中能确定唯一的 Java Class 对象。

下面的案例展示了上文中的 User 对象的 schema 信息。但是当前案例包含了一个指定文件目录的 namespace(当前案例下的包路径),反射过程中可以找到对应的 User 类。

// avro schema with namespace
final String schema = "{\"type\": \"record\", "+ "\"name\": \"User\", "+ "\"namespace\": \"org.apache.flink.formats.parquet.avro\", "+ "\"fields\": [\n"+ "        {\"name\": \"name\", \"type\": \"string\" },\n"+ "        {\"name\": \"favoriteNumber\",  \"type\": [\"int\", \"null\"] },\n"+ "        {\"name\": \"favoriteColor\", \"type\": [\"string\", \"null\"] }\n"+ "    ]\n"+ "    }";

由上述 scheme 信息创建的 Parquet 文件包含以下 meta 信息:

creator:        parquet-mr version 1.12.2 (build 77e30c8093386ec52c3cfa6c34b7ef3321322c94)
extra:          parquet.avro.schema =
{"type":"record","name":"User","namespace":"org.apache.flink.formats.parquet.avro","fields":[{"name":"name","type":"string"},{"name":"favoriteNumber","type":["int","null"]},{"name":"favoriteColor","type":["string","null"]}]}
extra:          writer.model.name = avrofile schema:    org.apache.flink.formats.parquet.avro.User
--------------------------------------------------------------------------------
name:           REQUIRED BINARY L:STRING R:0 D:0
favoriteNumber: OPTIONAL INT32 R:0 D:1
favoriteColor:  OPTIONAL BINARY L:STRING R:0 D:1row group 1:    RC:3 TS:143 OFFSET:4
--------------------------------------------------------------------------------
name:            BINARY UNCOMPRESSED DO:0 FPO:4 SZ:47/47/1.00 VC:3 ENC:PLAIN,BIT_PACKED ST:[min: Jack, max: Tom, num_nulls: 0]
favoriteNumber:  INT32 UNCOMPRESSED DO:0 FPO:51 SZ:41/41/1.00 VC:3 ENC:RLE,PLAIN,BIT_PACKED ST:[min: 1, max: 3, num_nulls: 0]
favoriteColor:   BINARY UNCOMPRESSED DO:0 FPO:92 SZ:55/55/1.00 VC:3 ENC:RLE,PLAIN,BIT_PACKED ST:[min: green, max: yellow, num_nulls: 0]

使用包 org.apache.flink.formats.parquet.avro 路径下已定义的 User 类:

public class User {private String name;private Integer favoriteNumber;private String favoriteColor;public User() {}public User(String name, Integer favoriteNumber, String favoriteColor) {this.name = name;this.favoriteNumber = favoriteNumber;this.favoriteColor = favoriteColor;}public String getName() {return name;}public Integer getFavoriteNumber() {return favoriteNumber;}public String getFavoriteColor() {return favoriteColor;}
}

可以通过下面的程序读取类型为 User 的 Avro Reflect records:

final FileSource<GenericRecord> source =FileSource.forRecordStreamFormat(AvroParquetReaders.forReflectRecord(User.class), /* Flink Path */).build();
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();env.enableCheckpointing(10L);final DataStream<GenericRecord> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");
7.Text files format

Flink 支持使用 TextLineInputFormat 从文件中读取文本行,此 format 使用 Java 的内置 InputStreamReader 以支持的字符集编码来解码字节流。 要使用该 format,需要将 Flink Connector Files 依赖项添加到项目中:

<dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-files</artifactId><version>1.19.0</version>
</dependency>

此 format 与新 Source 兼容,可以在批处理和流模式下使用;可以通过两种方式使用此 format:

  • 批处理模式的有界读取
  • 流模式的连续读取:监视目录中出现的新文件

有界读取示例

在此示例中,创建了一个 DataStream,其中包含作为字符串的文本文件的行。 此处不需要水印策略,因为记录不包含事件时间戳。

final FileSource<String> source =FileSource.forRecordStreamFormat(new TextLineInputFormat(), /* Flink Path */).build();
final DataStream<String> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");

连续读取示例:在此示例中,创建了一个 DataStream,随着新文件被添加到目录中,其中包含的文本文件行的字符串流将无限增长。每秒会进行新文件监控。 此处不需要水印策略,因为记录不包含事件时间戳。

final FileSource<String> source =FileSource.forRecordStreamFormat(new TextLineInputFormat(), /* Flink Path */).monitorContinuously(Duration.ofSeconds(1L)).build();
final DataStream<String> stream =env.fromSource(source, WatermarkStrategy.noWatermarks(), "file-source");

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

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

相关文章

人脸检测+调整分辨率+调整帧率

初始检测&#xff1a;只在视频的前几秒内进行一次人脸检测&#xff0c;以确定主持人的大致位置。计算裁剪框&#xff1a;基于检测到的主持人位置&#xff0c;计算一个以主持人面部为中心的固定裁剪框。视频裁剪&#xff1a;使用计算出的裁剪框对整个视频进行裁剪&#xff0c;将…

一文学会用RKE部署高可用Kubernetes集群

k8s架构图 RKE简介 RKE全称Rancher Kubernetes Engine&#xff0c;是一个快速的&#xff0c;多功能的 Kubernetes 安装工具。通过RKE&#xff0c;我们可以快速的安装一个高可用K8S集群。RKE 支持多种操作系统&#xff0c;包括 MacOS、Linux 和 Windows。 K8S原生安装需要的先…

【YOLOv5/v7改进系列】改进池化层为SimSPPF

一、导言 SimSPPF&#xff08;Simplified Spatial Pyramid Pooling with Fixed-size kernel&#xff09;模块是在YOLOv6架构中引入的一个关键组件&#xff0c;它旨在优化原始SPPF&#xff08;Spatial Pyramid Pooling Fixed-size&#xff09;模块的效率。以下是SimSPPF的一些优…

开发TEE的踩坑之开发TEE

系统&#xff1a;Ubuntu20.04&#xff08;双系统&#xff0c;非虚拟机&#xff09; 一、前置说明1、TEE平台的选择2、机器间的通信方式3、程序和数据集的示例4、结果文件的解密 二、服务器部署三、客户端部署四、工程应用 本系列为笔者开发TEE&#xff08;Trusted Execution En…

JS和jQuery操作表单常见的错误用法

设置radio选中 正确用法&#xff1a; //jquery $([name"sex"][value"1"]).prop(checked, true); $([name"sex"][value"1"])[0].checked true; //so, js method is: document.getElementById(youRadioId).checked true;错误用法 $([n…

【笔记】虚拟机中的主从数据库连接实体数据库成功后的从数据库不同步问题解决方法2

错误&#xff1a; Last_Errno: 1008 Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction ANONYMOUS at source log mysql-bin.000014, end_log_pos 200275. See error lo…

开放式耳机哪款好一点?开放式耳机科普五款推荐!

“选择开放式耳机真的太难了” “哥&#xff0c;怎么才能选到心仪的开放式耳机啊” 这种评论总是会出现后台或者现实的朋友也会问起来&#xff0c;所以作为耳机测评的博主&#xff0c;在这里给大家科普一下到底一款好用的开放式耳机到底怎么选&#xff0c;这篇文章我花了三天…

Centos系统内磁盘分区

Centos系统内磁盘分区 建议如果有重要数据提前做好备份 以根目录扩容50G为例&#xff1a; 1、卸载/home目录 umount /home 2、删除逻辑卷 y确认即可 lvremove /dev/mapper/centos-home 3、df -h查询一下&#xff0c;/home目录已经不见了 4、向根目录分区追加50G容量 lv…

网易云小程序资料分享

链接: https://pan.baidu.com/s/1jzP52Zq4R-nUTxN334XMJg 提取码: xhny

如何看待AI机器人取代人工拨打电话

所以整理了以下几点机器人呢拨打的流程​&#xff1a; 1. 效率提升 AI机器人能够自动拨打电话&#xff0c;并快速处理大量电话任务&#xff0c;这在很大程度上提高了效率。在销售和客户服务等领域&#xff0c;这种高效的工作方式能够极大地节省时间&#xff0c;并有可能带来业…

[XCUITest] 处理iOS权限点击授权 有哪些权限?

位置权限 (Location Permission) app.addUIInterruptionMonitor(withDescription: "Location Permission Dialog") { (alert) -> Bool in if alert.buttons["Allow While Using App"].exists { alert.buttons["Allow While Using App"].tap(…

Android --- Android 8.0之后不允许在后台启动一个服务的解决方案

从Android 8.0&#xff08;API级别26&#xff09;开始&#xff0c;Google 引入了后台服务限制&#xff0c;目的是为了改善系统资源管理和用户体验。这些限制导致在后台运行的服务可能会被系统认为是无效的&#xff0c;从而限制或者终止这些服务。针对这个问题&#xff0c;可以考…

STM32基础篇:EXTI × 事件 × EXTI标准库

EXTI EXTI简介 EXTI&#xff1a;译作外部中断/事件控制器&#xff0c;STM32的众多片上外设之一&#xff0c;能够检测外部输入信号的边沿变化并由此产生中断。 例如&#xff0c;在检测按键时&#xff0c;按键按下时会使电平产生翻转&#xff0c;因此可以使用EXTI来读取按下时…

线上线下一体开源的Hugging Face?| 这些问题不可不看……

7月&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议&#xff08;WAIC 2024&#xff09;在上海盛大启幕&#xff0c;以“以共商促共享&#xff0c;以善治促善智”为主题进行展览&#xff0c;OpenCSG首次亮相“CSGHub和StarShip”两大产品&#xff0c;全方位展现公…

HTML5新增的input元素类型:number、range、email、color、date等

HTML5 大幅度地增加与改良了 input 元素的种类&#xff0c;可以简单地使用这些元素来实现 HTML5 之前需要使用 JavaScript 才能实现的许多功能。 到目前为止&#xff0c;大部分浏览器都支持 input 元素的种类。对于不支持新增 input 元素的浏览器&#xff0c;input 元素被统一…

kotlin数据容器

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 容器是用于存放数据的载体。容器分为数组、集合。 Kotlin作为一门全新的语言&#xff0c;肯定还是要有自己的容…

网优学习干货:xx5G速率优化现场实战版

速率概述 无线网络仍然是5G网络能力最容易受限的环节&#xff0c;无线网络技术的应用将最终决定5G网络能力的木桶深度。移动通信中传统关键技术在5G将会继续使用。5G NR在继承了LTE原有部分技术基础上&#xff0c;采用了一些技术演进和新技术创新。比如NR继承了LTE的OFDM和SC-…

ArduPilot开源飞控之AP_Mount_Topotek

ArduPilot开源飞控之AP_Mount_Topotek 1. 源由2. 框架设计3. 重要函数3.1 动态过程3.1.1 AP_Mount_Topotek::update3.1.2 AP_Mount_Backend::calculate_poi 3.2 基础能力3.2.1 AP_Mount_Topotek::healthy3.2.2 AP_Mount_Topotek::has_pan_control 3.3 设备功能3.3.1 AP_Mount_T…

深入剖析 Java 中 Spring Bean 的生命周期

在 Java 开发中&#xff0c;Spring 框架是广泛使用的企业级应用开发框架。理解 Spring Bean 的生命周期对于开发者来说至关重要&#xff0c;这也是面试中经常会被问到的重要知识点。 一、Spring Bean 的定义与创建 Spring Bean 是由 Spring 容器管理的对象。Spring 容器在创建…

Winform打印编程基础

1、目的 进行打印设置、打印预览、及实现打印功能 2、代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Printing; using System.IO; using System.Linq; using System.Te…