# ohos_avro
**Repository Path**: codeeeeeee/ohos_avro
## Basic Information
- **Project Name**: ohos_avro
- **Description**: avro的c库鸿蒙化适配
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2025-08-04
- **Last Updated**: 2025-09-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# avro
## 简介
> 本软件是参照开源软件[apache avro](https://github.com/apache/avro)源码适配OpenHarmony实现的数据序列化系统,支持丰富的数据结构,将其转化成便于存储或传输的二进制数据格式。它同时也是一个容器文件,用于存储持久数据。
## 效果展示:
## 下载安装
````
ohpm install @ohos/avro
````
OpenHarmony ohpm 环境配置等更多内容,请参考[如何安装 OpenHarmony ohpm 包](https://gitcode.com/openharmony-tpc/docs/blob/master/OpenHarmony_har_usage.md)
## 使用说明
### 示例代码
1. 在page页面中引入avro
```
import {OhosAvroC, toFile, fromFile} from '@ohos/avro';
```
2. 使用
```js
// int 类型
let psInt : AvroNapi = new AvroNapi();
let intStr: string = "{type: 'int'}";
psInt.parse(intStr)
let intBuf : number =123;
let bufInt: ArrayBuffer = psInt.toBuffer(intBuf); // 序列化
let u8BufInt = new Uint8Array(bufInt);
console.log('testTag toBuffer int =', JSON.stringify(u8BufInt));// result:{"0":246,"1":1}
let fromInt: number = psInt.fromBuffer(bufInt); // 反序列化
console.log('testTag fromBuffer int =', fromInt);//result:123
console.log('testTag int getName=', psInt.getName());//name:int
console.log('testTag isValid int value:123=', psInt.isValid(intBuf));//数据匹配
// string 类型
let psString: AvroNapi = new AvroNapi();
let stringStr: string = "{type: 'string'}";
psString.parse(stringStr);
let stringBuf : string ='sdf234';
let bufString: ArrayBuffer = psString.toBuffer(stringBuf);
let u8BufString = new Uint8Array(bufString);
//result:{"0":12,"1":115,"2":100,"3":102,"4":50,"5":51,"6":52}
console.log('testTag toBuffer string =', JSON.stringify(u8BufString));
let fromString: object = psString.fromBuffer(bufString);
//result:"sdf234"
console.log('testTag fromBuffer string:'+JSON.stringify(fromString));
//name:string
console.log('testTag string getName=', psString.getName());
//数据匹配
console.log('testTag isValid string=', psString.isValid(stringBuf));
// fixed类型
let psFixed : AvroNapi = new AvroNapi();
let fixedStr: string = "{type: 'fixed', name: 'num', aliases: ['stooges1', 'stooges2'], size: 2, namespace: 'a'}";
psFixed.parse(fixedStr)
let fixedBuf =[0x67, 0xAB];
let buffixed: ArrayBuffer = psFixed.toBuffer(fixedBuf);
let u8BufFixed = new Uint8Array(buffixed);
//result:{"0":103,"1":171}
console.log('testTag toBuffer fixed =', JSON.stringify(u8BufFixed));
const fromFix:object = psFixed.fromBuffer(buffixed);
//result:[103,171](16进制为[0x67, 0xAB])
console.log('testTag fromBuffer fixed =', JSON.stringify(fromFix));
//name:num
console.log('testTag fixed getName=', psFixed.getName());
//数据匹配
console.log('testTag isValid fixed=', psFixed.isValid(fixedBuf));
//当前Fixed的size:2
console.log('testTag getFixedSize=', psFixed.getFixedSize());
let aliasesFixed:Array = psFixed.getAliases();
//result:["stooges1","stooges2"]
console.log('testTag getAliases fixed =', JSON.stringify(aliasesFixed));
let schemaFixed:string = psFixed.getSchema();
//result(avro格式的):"{\"type\": \"fixed\", \"name\": \"num\", \"aliases\": [\"stooges1\", \"stooges2\"], \"size\": 2, \"namespace\": \"a\"}"
console.log('testTag getSchema fixed =', JSON.stringify(schemaFixed));
// 数组类型
let psArray : AvroNapi = new AvroNapi();
let arrayStr: string = "{type: 'array', items: 'string'}";
psArray.parse(arrayStr)
let arrayBuf =['3443rtr', 'sfrf', 'eryryyh'];
let bufarray: ArrayBuffer = psArray.toBuffer(arrayBuf);
let u8BufArray = new Uint8Array(bufarray);
//result:{"0":6,"1":14,"2":51,"3":52,"4":52,"5":51,"6":114,"7":116,"8":114,"9":8,"10":115,"11":102,"12":114,"13":102,"14":14,"15":101,"16":114,"17":121,"18":114,"19":121,"20":121,"21":104,"22":0}
console.log('testTag toBuffer array =', JSON.stringify(u8BufArray));
const fromArray:object = psArray.fromBuffer(bufarray);
//result:["3443rtr","sfrf","eryryyh"]
console.log('testTag fromBuffer array =', JSON.stringify(fromArray));
//name:array
console.log('testTag Array getName=', psArray.getName());
//数据匹配
console.log('testTag isValid array=', psArray.isValid(arrayBuf));
//当前数组的类型为:string
console.log('testTag getArrayItemType=', psArray.getArrayItemType());
// map 类型
let psMap: AvroNapi = new AvroNapi();
let mapStr: string = "{type: 'map', values: 'long'}";
psMap.parse(mapStr)
const data = new Map([["key1",12343], ["key2",3445]]);
let bufmap: ArrayBuffer = psMap.toBuffer(data);
let u8Bufmap = new Uint8Array(bufmap);
//result:{"0":4,"1":8,"2":107,"3":101,"4":121,"5":49,"6":238,"7":192,"8":1,"9":8,"10":107,"11":101,"12":121,"13":50,"14":234,"15":53,"16":0}
console.log('testTag toBuffer map =', JSON.stringify(u8Bufmap));
const aa:object = psMap.fromBuffer(bufmap);
//result:{"key1":12343,"key2":3445}
console.log('testTag fromBuffer map:'+ JSON.stringify(aa));
//name:map
console.log('testTag Map getName=', psMap.getName());
//数据匹配
console.log('testTag isValid map=', psMap.isValid(data));
//当前Map的类型为:long
console.log('testTag getMapValueType=', psMap.getMapValueType());
// record 类型
let psRecord : AvroNapi = new AvroNapi();
let recordStr: string = "{type: 'record',name: 'Person',aliases: ['Person1'],fields: [{name: 'age', type: 'int'}, {name: 'name', type: 'string'}]}";
psRecord.parse(recordStr);
class petrecordType {
"age": number = 0
"name": string = ''
}
let recordBuf : petrecordType ={"age": 25, "name": "Alice"};
let bufrecord: ArrayBuffer = psRecord.toBuffer(recordBuf);
let u8BufRecord = new Uint8Array(bufrecord);
//result:{"0":50,"1":10,"2":65,"3":108,"4":105,"5":99,"6":101}
console.log('testTag toBuffer record ='+JSON.stringify(u8BufRecord));
const recFromBuff:object = psRecord.fromBuffer(bufrecord);
//result:{"age":25,"name":"Alice"}
console.log('testTag fromBuffer record ='+JSON.stringify(recFromBuff));
//name:Person
console.log('testTag Record getName=', psRecord.getName());
//数据匹配
console.log('testTag isValid record=', psRecord.isValid(recordBuf));
let aliasesRec:Array = psRecord.getAliases();
//result:["Person1"]
console.log('testTag getAliases record =', JSON.stringify(aliasesRec));
let schemaRec:string = psRecord.getSchema();
//result(avro格式的):"{\"type\": \"record\",\"name\": \"Person\",\"aliases\": [\"Person1\"],\"fields\": [{\"name\": \"age\", \"type\": \"int\"}, {\"name\": \"name\", \"type\": \"string\"}]}"
console.log('testTag getSchema record =', JSON.stringify(schemaRec));
// compareBuffers
const hexArray = [0x67, 0xAB];
const uArray = new Uint8Array(hexArray);
const buffer1 = uArray.buffer;
const hexArray2 = [0x67, 0xAB, 0x11];
const uArray2 = new Uint8Array(hexArray2);
const buffer2 = uArray2.buffer;
console.log("testTag compareBuffers :" + psArray.compareBuffers(buffer1, buffer2));//小于
// tofile
//定义回调函数
let fileSchemaStr: string = "{type: 'record',name: 'User',namespace: 'comexample',fields: [ {name: 'id', type: 'int'}, {name: 'name', type: 'string'}, {name: 'age', type: ['int', 'null']},{name: 'hobbies',type:{type:'array',items: 'string'}}]}";
const path2 = getContext(this).getApplicationContext().filesDir+"/10.avro";
class petrecordType6 {
"id": number = 0
"name": string = ''
"age": number | null
"hobbies": Array
}
let recordBuf7 = new petrecordType6();
recordBuf7.id = 1;
recordBuf7.name = "san";
recordBuf7.age = 25;
recordBuf7.hobbies = ["yd", "pb"];
let recordBuf8 = new petrecordType6();
recordBuf8.id = 2;
recordBuf8.name = "si";
recordBuf8.age = null;
recordBuf8.hobbies = ["yy", "lx"];
let recordBuf9 = new petrecordType6();
recordBuf9.id = 3;
recordBuf9.name = "wu";
recordBuf9.age = 30;
recordBuf9.hobbies = ["bc", "yy"];
let fileArrayBuf1 =[recordBuf7, recordBuf8, recordBuf9];
//压缩方式支持"deflate"(zlib) "snappy" "lzma" "null"无压缩
try {
toFile(path, schema, fileArrayBuf1, "null", (error, data) => {
if (error != undefined) {
console.log('testTag 序列化失败, error:', error);
this.showAlert('序列化失败', '错误信息:' + error);
}
if (data === undefined) {
console.log('testTag 数据有问题!');
this.showAlert('序列化失败', '数据有问题!');
} else {
console.error('ps has been created tofile:' + data);
this.showAlert('序列化成功', '数据:' + data);
}
});
} catch (error) {
console.log('序列化失败:', error);
}
// fromfile
let fileSchemaStr: string = "{type: 'record',name: 'User',namespace: 'comexample',fields: [ {name: 'id', type: 'int'}, {name: 'name', type: 'string'}, {name: 'age', type: ['int', 'null']},{name: 'hobbies',type:{type:'array',items: 'string'}}]}";
const path2 = getContext(this).getApplicationContext().filesDir+"/10.avro";
try {
fromFile(path2, fileSchemaStr, (error, buffer) => {
if (error != undefined) {
console.log('testTag 反序列化失败:', error);
this.showAlert('反序列化失败', '错误信息:' + error);
}
if (buffer === undefined) {
console.log('testTag 反序列化失败,数据有你为他!');
this.showAlert('反序列化失败', '数据有问题!');
} else {
//[{"id":1,"name":"san","age":25,"hobbies":["yd","pb"]},{"id":2,"name":"si","age":null,"hobbies":["yy","lx"]},{"id":3,"name":"wu","age":30,"hobbies":["bc","yy"]}]
console.error('testTag 反序列化结果:', JSON.stringify(buffer));
this.showAlert('序列化成功', '反序列化结果:' + JSON.stringify(buffer));
}
});
} catch (error) {
console.log('反序列化失败:', error);
}
```
## 接口说明
| 方法名 | 参数 | 接口描述 |
| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: |
| parse(schema:string) | schema:Avro模式定义 | 解析schema并返回对应的实例 |
| toBuffer(val:any) | val: 符合模式的数据对象 | 将数据对象编码序列化为Avro二进制格式的ArrayBuffer |
| fromBuffer(buf:ArrayBuffer) | buffer: Avro 编码的二进制数据 | 从Avro二进制格式的ArrayBuffer反序列化为对应类型的数据 |
| isValid(val:any) | val:待验证的数据 | 检查给定值是否是有效值。 |
| compareBuffers(buf1:ArrayBuffer, buf2:ArrayBuffer) | buf1:待比较的缓冲区
buf2:待比较的缓冲区 | 比较两个二进制缓冲区的大小。返回值说明(按字段定义顺序逐字段比较):
● 负数:val1 < val2
● 0:val1 == val2
● 正数:val1 > val2 |
| getName() | - | 获取类型的名称。 |
| getArrayItemType() | - | 获取数组的类型。 |
| getFixedSize() | - | 获取Fixed类型的大小。 |
| getMapValueType() | - | 获取Map的类型。 |
| getSchema() | - | 获取Schema字符串,返回的是avro格式的字符串(属性和字符字段都加双引号) |
| getAliases() | - | 获取别名(只有Enum、Fixed、Record有name属性,才有别名),结果为字符串数组 |
| toFile(path: string, schema: string, val: any, codec: string, callback:AsyncWriteFileCallback) | path:文件路径
schema:Avro模式定义
val:要序列化的数据(record类型支持多条数据传输,record类型请按照数组的形式传递)
codec:压缩方式
callback:异步写文件完成的回调,参数err: string, data: string | 将record数据对象使用指定的schema模式序列化到文件(压缩方式支持"deflate"(zlib) "snappy" "lzma" "null"无压缩)。 |
| fromFile(filePath:string,scheam:string,callback:callback) | filePath:文件路径
schema:Avro模式定义
callback:异步读取文件完成的回调,参数err: string, data: ArrayBuffer | 读取已经序列化后的文件使用指定的schema模式转为record类型数据(ArrayBuffer) |
## 关于混淆
- 代码混淆,请查看[代码混淆简介](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/arkts-utils/source-obfuscation.md)
- 如果希望avro-js库在代码混淆过程中不会被混淆,需要在混淆规则配置文件obfuscation-rules.txt中添加相应的排除规则:
```
---
```
## 约束与限制
在下述版本验证通过:
- DevEco Studio 版本:DevEco Studio 5.0.5 Release, OpenHarmony SDK:5.0.5(17)
## 目录结构
````
|---- ohos_avro
| |---- entry # 示例代码文件夹
| |---- avro # avro 库文件夹
| |---- cpp # native模块
| |----- napi # napi实现代码目录
| |----- third_party # 实现引用的三方库jansson、avro、snappy、zlib、lzma
| |----- utils # 工具、公共代码和日志接口目录
| |----- type # 对外接口函数目录
| |---- README_zh.MD # 安装使用方法
````
## 贡献代码
使用过程中发现任何问题都可以提 [Issue](https://gitcode.com/openharmony-sig/avro/issues) 给组件,当然,也非常欢迎给发 [PR](https://gitcode.com/openharmony-sig/avro/pulls)
。
## 开源协议
本项目基于 [Apache License 2.0](https://gitcode.com/openharmony-sig/avro/blob/master/LICENSE) ,请自由地享受和参与开源。