uniapp结合腾讯云及时通信IM的聊天记录本地存储方案
uniapp结合腾讯云及时通信IM的聊天记录本地存储方案
UniApp 是一个跨平台的应用开发框架,可以使用 Vue.js 开发多端应用(如H5、小程序、App等)。在 UniApp 中,可以使用 uni-app 提供的文件系统 API 完成本地文件存储的操作。
1.具体实现方式如下:
创建一个用于存储聊天记录的目录,可以使用 uni-app 提供的 uni.getFileSystemManager
API 创建:
uni.getFileSystemManager().mkdirSync(`${uni.env.USER_DATA_PATH}/chat`);
将聊天记录以文件的形式存储在该目录下,可以使用 fs.writeFileSync
API 实现:
const chatContent = '这是一条聊天记录'; // 假设聊天记录内容为字符串
const fileName = 'chatRecord_001.txt'; // 文件名可以按照一定的规则生成try {uni.getFileSystemManager().writeFileSync(`${uni.env.USER_DATA_PATH}/chat/${fileName}`, chatContent, 'utf-8');
} catch (e) {console.error(e);
}
读取本地存储的聊天记录,可以使用 fs.readFileSync
API 实现:
const fileName = 'chatRecord_001.txt';try {const chatContent = uni.getFileSystemManager().readFileSync(`${uni.env.USER_DATA_PATH}/chat/${fileName}`, 'utf-8');console.log(chatContent);
} catch (e) {console.error(e);
}
结合腾讯云即时通信IM开发聊天软件时,可以使用uni-app提供的本地存储API将聊天记录存储在本地,具体实现方案如下:
1.1 初始化聊天记录:
当用户进入聊天界面时,可以通过查询本地存储是否存在聊天记录,如果不存在则新建一个聊天记录文件,同时将腾讯云IM服务端的聊天记录下载到本地存储中。
// 初始化聊天记录,userId表示当前用户的ID,toUserId表示聊天对象的ID
function initChatRecords(userId, toUserId) {const fileName = `chat_${userId}_${toUserId}.json`;const fileContent = {chatHistory: [], // 聊天记录数组lastReadTime: Date.now(), // 最后一条已读消息的时间戳};try {const chatContent = uni.getStorageSync(fileName);if (chatContent) {// 本地存储中已经存在聊天记录,直接读取const chatRecords = JSON.parse(chatContent);fileContent.chatHistory = chatRecords.chatHistory;fileContent.lastReadTime = chatRecords.lastReadTime;} else {// 本地存储中不存在聊天记录,从IM服务器下载并保存到本地getChatHistory(userId, toUserId).then((res) => {if (res.data) {const chatHistory = formatChatHistory(res.data);fileContent.chatHistory = chatHistory;uni.setStorageSync(fileName, JSON.stringify(fileContent));}});}} catch (e) {console.error(e);}return fileContent;
}
1.2 存储聊天记录:
当用户发送一条聊天消息时,将该消息存储到本地的聊天记录文件中,同时更新最后一条已读消息的时间戳。
// 存储聊天记录,userId表示当前用户的ID,toUserId表示聊天对象的ID,message表示聊天消息对象
function saveChatRecord(userId, toUserId, message) {const fileName = `chat_${userId}_${toUserId}.json`;try {const chatContent = uni.getStorageSync(fileName);if (chatContent) {const chatRecords = JSON.parse(chatContent);chatRecords.chatHistory.push(message);uni.setStorageSync(fileName, JSON.stringify(chatRecords));}} catch (e) {console.error(e);}
}
1.3 更新聊天记录:
当用户接收到新的聊天消息时,将该消息存储到本地的聊天记录文件中,同时更新最后一条已读消息的时间戳。
// 更新聊天记录,userId表示当前用户的ID,toUserId表示聊天对象的ID,message表示聊天消息对象
function updateChatRecord(userId, toUserId, message) {const fileName = `chat_${userId}_${toUserId}.json`;try {const chatContent = uni.getStorageSync(fileName);if (chatContent) {const chatRecords = JSON.parse(chatContent);chatRecords.chatHistory.push(message);chatRecords.lastReadTime = Date.now(); // 更新最后一条已读消息的时间戳
2.更详细的实现方案:
2.1 聊天记录的本地存储
在uni-app中,可以使用uni-storage插件来实现本地存储。为了方便管理,可以将每个聊天对象的聊天记录存储在单独的文件中。例如,对于一个名为A的用户和一个名为B的用户的聊天记录,可以将它们存储在一个名为chat_A_B.json
的文件中。
为了确保在保存数据时出现任何错误时能够及时捕获和处理异常,我们可以在代码中使用try-catch
块。当我们从本地存储中读取聊天记录时,需要检查该文件是否存在,如果不存在,则需要创建一个空的聊天记录文件。
以下是一个简单的实现示例:
// 存储聊天记录
function saveChatRecord(userId, toUserId, message) {const fileName = `chat_${userId}_${toUserId}.json`;try {const chatContent = uni.getStorageSync(fileName) || '{"chatHistory": []}';const chatRecords = JSON.parse(chatContent);chatRecords.chatHistory.push(message);uni.setStorageSync(fileName, JSON.stringify(chatRecords));} catch (e) {console.error(e);}
}// 读取聊天记录
function readChatRecords(userId, toUserId) {const fileName = `chat_${userId}_${toUserId}.json`;try {const chatContent = uni.getStorageSync(fileName) || '{"chatHistory": []}';return JSON.parse(chatContent).chatHistory;} catch (e) {console.error(e);return [];}
}
2.2 聊天记录的初始化
在用户打开聊天窗口时,我们需要确保该聊天记录文件存在。如果文件不存在,则需要从服务器获取聊天记录,并将其存储到本地文件中。
以下是一个示例代码:
function initChatRecords(userId, toUserId) {const fileName = `chat_${userId}_${toUserId}.json`;const fileContent = {chatHistory: [],lastReadTime: Date.now(),};try {const chatContent = uni.getStorageSync(fileName);if (chatContent) {// 如果文件存在,则读取文件中的聊天记录const chatRecords = JSON.parse(chatContent);fileContent.chatHistory = chatRecords.chatHistory;fileContent.lastReadTime = chatRecords.lastReadTime;} else {// 如果文件不存在,则从服务器获取聊天记录,并存储到本地文件中getChatHistory(userId, toUserId).then((res) => {if (res.data) {const chatHistory = formatChatHistory(res.data);fileContent.chatHistory = chatHistory;uni.setStorageSync(fileName, JSON.stringify(fileContent));}});}} catch (e) {console.error(e);}return fileContent;
}
在上述代码中,getChatHistory
函数用于从服务器获取聊天记录,formatChatHistory
函数用于将服务器返回的聊天记录格式化为符合本地存储要求的格式。
2.3 如何标记已读消息
我们可以在本地存储中为每个聊天记录文件添加一个lastReadTime
属性来标记最后一次已读消息的时间戳。当用户打开聊天窗口时,我们可以将该属性更新为当前时间戳,表示用户已经查看了该聊天记录中的所有消息。
以下是一个示例代码:
// 标记聊天记录已读
function markChatRecordAsRead(userId, toUserId) {const fileName = `chat_${userId}_${toUserId}.json`;const chatContent = uni.getStorageSync(fileName);if (chatContent) {try {const chatRecords = JSON.parse(chatContent);chatRecords.lastReadTime = Date.now();uni.setStorageSync(fileName, JSON.stringify(chatRecords));} catch (e) {console.error(e);}}
}
2.4 何时修改本地存储
我们需要在以下情况下更新本地存储:
- 当用户发送一条新的聊天消息时,将该消息存储到本地文件中。
- 当用户打开聊天窗口时,需要初始化该聊天记录文件。如果该文件不存在,则需要从服务器获取聊天记录,并将其存储到本地文件中。
- 当用户查看聊天记录时,需要将
lastReadTime
属性更新为当前时间戳,表示已读。
需要注意的是,我们需要确保所有本地存储的操作都是异步的,以避免阻塞应用程序。
2.5 如何在App中读取本地聊天记录
在App中,我们可以根据用户选择的聊天对象,读取该聊天对象的聊天记录文件。例如,如果用户选择与B用户聊天,则我们可以读取chat_A_B.json
文件中的聊天记录。
以下是一个示例代码:
function loadChatRecords(userId, toUserId) {const fileName = `chat_${userId}_${toUserId}.json`;try {const chatContent = uni.getStorageSync(fileName);if (chatContent) {const chatRecords = JSON.parse(chatContent);return chatRecords.chatHistory;}} catch (e) {console.error(e);}return [];
}
在上述代码中,loadChatRecords
函数用于从本地存储中读取指定聊天记录文件中的聊天记录。
总结
综上所述,我们可以使用uni-storage插件实现聊天记录的本地存储,并使用lastReadTime
属性来标记已读消息。当用户打开聊天窗口时,我们需要初始化该聊天记录文件。如果该文件不存在,则需要从服务器获取聊天记录,并将其存储到本地文件中。当用户发送一条新的聊天消息时,将该消息存储到本地文件中。在App中,我们可以根据用户选择的聊天对象,读取该聊天对象的聊天记录文件。
3.遇到的问题
除了以上提到的实现方案外,还有一些细节问题需要考虑。以下是一些需要注意的点:
3.1 本地存储容量限制
不同的平台和设备可能对本地存储容量有不同的限制,因此我们需要根据实际情况来确定每个聊天记录文件的最大容量,并及时清理过期的聊天记录。否则,当本地存储空间不足时,将无法存储新的聊天记录。
3.2 聊天记录加密
为了保护用户隐私,我们应该将聊天记录进行加密处理。可以使用一些加密算法来对聊天记录文件进行加密,以确保用户的聊天记录不会被窃取。
3.3 消息同步
如果用户在不同的设备上使用同一个账号登录,那么他们的聊天记录应该能够同步到所有设备上。因此,在本地存储方案中,我们需要考虑如何实现聊天记录的同步。
可以使用云存储服务,如腾讯云对象存储,来实现聊天记录的云端存储和同步。每当用户在一个设备上发送了一条新的聊天消息时,我们可以将该消息同步到云端存储中。而当用户在另一个设备上打开聊天窗口时,我们可以从云端存储中获取最新的聊天记录,并将其更新到本地存储中。
3.4 数据备份
由于本地存储存在数据丢失的风险,我们需要定期对聊天记录进行备份。可以将聊天记录文件上传到云存储服务中,并在需要恢复数据时,从云存储中下载备份数据。
总结
以上是实现uniapp结合腾讯云及时通信IM开发聊天软件的聊天记录本地存储方案。在实际应用中,我们需要考虑到各种细节问题,如本地存储容量限制、聊天记录加密、消息同步和数据备份等。通过对这些问题进行细致的考虑和处理,我们可以为用户提供更加稳定和安全的聊天体验。
4.怎么解决本地存储容量限制问题?
当本地存储空间不足时,我们可以通过以下几种方式来解决:
4.1 清理过期的聊天记录
我们可以在应用中实现一个定期清理聊天记录的功能,将过期的聊天记录文件删除,从而释放存储空间。这可以通过设置定期清理的时间间隔或根据存储空间的占用率来触发清理操作。
4.2 使用本地缓存
可以使用一些本地缓存机制来存储聊天记录,如使用 uni-app 内置的本地存储 API(如 localStorage、sessionStorage)来存储数据。这种方式可以帮助我们充分利用设备的存储空间,并且可以通过设置缓存过期时间来控制存储的数据大小。
4.3 利用云存储
我们可以将聊天记录存储到云端,使用云存储服务来解决本地存储空间不足的问题。当用户在本地存储空间不足时,我们可以通过下载云端聊天记录来缓解本地存储空间的压力。
4.4 优化聊天记录文件大小
我们可以通过优化聊天记录文件的大小来减少本地存储空间的占用。比如可以压缩聊天记录中的图片、视频等多媒体文件,或者将多个聊天记录文件合并成一个文件等方式。
总之,我们需要在开发应用的过程中注意本地存储空间的使用情况,并在必要时采取相应的措施来解决空间不足的问题。同时,为了提高用户体验,我们需要在保证数据安全的前提下,尽可能地扩大应用所能使用的存储空间。
5.怎么解决聊天记录加密问题,比如加密和解密?
聊天记录的加密问题一般可以通过对消息内容进行加密来解决。在实现聊天记录加密时,我们可以采用以下的方式:
5.1 使用对称加密算法
对称加密算法可以使用同一个密钥进行加密和解密操作,比如常用的 AES、DES 等算法。在使用对称加密算法时,发送方需要先使用密钥对消息内容进行加密,然后再发送给接收方,接收方则需要使用同样的密钥对消息内容进行解密。
5.2 使用非对称加密算法
非对称加密算法需要使用公钥和私钥来进行加密和解密操作,比如常用的 RSA 算法。在使用非对称加密算法时,发送方需要使用接收方的公钥对消息内容进行加密,然后再发送给接收方,接收方则需要使用自己的私钥对消息内容进行解密。
5.3 采用混合加密方案
混合加密方案是将对称加密算法和非对称加密算法结合起来使用,利用非对称加密算法来安全地传输对称加密算法的密钥,然后使用对称加密算法对消息内容进行加密和解密。这种方案既保证了数据的安全性,又能够提高加密和解密的效率。
无论采用哪种方式,实现聊天记录加密时还需要注意以下几点:
- 安全存储密钥
密钥的安全存储对于加密方案的安全性至关重要。我们应该采用安全的方式存储密钥,比如使用硬件模块来存储密钥,或者将密钥加密后再存储。
- 避免密钥泄露
密钥的泄露会导致加密方案失去作用,因此我们需要采取措施来避免密钥的泄露。比如限制密钥的使用范围、限制密钥的使用次数等。
- 处理加解密性能
加解密算法的性能会影响应用的响应速度,因此我们需要在实现加密方案时注意优化加解密算法的性能,比如使用硬件加速、缓存加解密结果等方式。
总之,在实现聊天记录加密时,我们需要权衡安全性和性能,采用合适的加密方案来保障数据的安全。同时还需要考虑密钥的管理、密钥的安全存储等问题。
5.4 示例代码
结合了聊天记录的存储和读取过程,同时采用了对称加密算法 AES 进行加密和解密。
// 加密消息
function encryptMessage(message, key) {const iv = crypto.getRandomValues(new Uint8Array(16)); // 生成随机的 IVconst encodedMessage = new TextEncoder().encode(message); // 将消息编码为字节数组const cipher = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encodedMessage); // 使用 AES-GCM 加密消息const encryptedMessage = new Uint8Array(iv.length + new Uint8Array(cipher).length);encryptedMessage.set(iv);encryptedMessage.set(new Uint8Array(cipher), iv.length); // 将 IV 和加密后的消息组合成一个字节数组return encryptedMessage;
}// 解密消息
async function decryptMessage(encryptedMessage, key) {const iv = encryptedMessage.slice(0, 16); // 从字节数组中获取 IVconst ciphertext = encryptedMessage.slice(16); // 从字节数组中获取加密后的消息const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext); // 使用 AES-GCM 解密消息return new TextDecoder().decode(plaintext); // 将解密后的字节数组转换为字符串
}// 存储聊天记录
function storeChatRecord(userId, chatRecord, key) {const encryptedRecord = encryptMessage(JSON.stringify(chatRecord), key); // 对聊天记录进行加密const fileName = `${userId}-chat-record.dat`;const blob = new Blob([encryptedRecord], { type: 'application/octet-stream' });const file = new File([blob], fileName);// 将加密后的聊天记录存储为本地文件window.requestFileSystem(window.PERSISTENT, 1024 * 1024, async (fs) => {const fileEntry = await createFile(fs.root, fileName);await writeFile(fileEntry, file);});
}// 读取聊天记录
async function loadChatRecord(userId, key) {const fileName = `${userId}-chat-record.dat`;// 从本地文件中读取加密后的聊天记录const file = await getFile(fileName);const encryptedRecord = await readFile(file);const chatRecord = await decryptMessage(encryptedRecord, key); // 对加密后的聊天记录进行解密return JSON.parse(chatRecord);
}// 生成 AES 密钥
async function generateAesKey() {return crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 },true,['encrypt', 'decrypt']);
}// 初始化聊天记录加密密钥
async function initChatRecordEncryption(userId) {const keyName = `${userId}-encryption-key`;let key = await getKey(keyName);if (!key) {key = await generateAesKey();await setKey(keyName, key);}return key;
}// 存储密钥
async function setKey(keyName, key) {const exportedKey = await crypto.subtle.exportKey('jwk', key);localStorage.setItem(keyName, JSON.stringify(exportedKey));
}// 获取密钥
async function getKey(keyName) {const exportedKey = localStorage.getItem(keyName);if (!exportedKey) {return null;}return crypto.subtle.importKey('jwk',JSON.parse(exportedKey),{ name: 'AES-GCM', length: 256 },true,['encrypt', 'decrypt']);
}// 创建文件
async function createFile(rootDirEntry, fileName) {return new Promise((resolve, reject) => {rootDirEntry.getFile(fileName,{ create: true, exclusive: false },resolve,reject);});
}// 写入文件
async function writeFile(fileEntry, file) {return new Promise((resolve, reject) => {fileEntry.createWriter((fileWriter) => {fileWriter.onwriteend = resolve;fileWriter.onerror = reject;fileWriter.write(file);});});
}// 获取文件
async function getFile(fileName) {return new Promise((resolve, reject) => {window.requestFileSystem(window.PERSISTENT, 1024 * 1024, (fs) => {fs.root.getFile(fileName,{},resolve,(error) => {if (error.code === FileError.NOT_FOUND_ERR) {// 如果文件不存在,返回空文件对象resolve(new File([], fileName));} else {reject(error);}});});});
}// 读取文件
async function readFile(file) {return new Promise((resolve, reject) => {const reader = new FileReader();reader.onloadend = () => {resolve(new Uint8Array(reader.result));};reader.onerror = reject;reader.readAsArrayBuffer(file);});
}
在实现过程中,我们使用 AES-GCM 对称加密算法进行加密和解密,同时采用了随机生成的 IV,增加了加密的强度和安全性。加密密钥使用 JWK 格式进行存储和导入,可以更方便地在不同的设备和浏览器之间共享和传输。在存储聊天记录时,我们将加密后的记录存储为一个二进制文件,通过 File API 和 File System API 实现对本地文件的读写操作。在读取聊天记录时,我们首先读取本地文件,并对其中的加密数据进行解密,再将解密后的数据转换为 JSON 格式,最后返回聊天记录对象。
相关文章:
uniapp结合腾讯云及时通信IM的聊天记录本地存储方案
uniapp结合腾讯云及时通信IM的聊天记录本地存储方案 UniApp 是一个跨平台的应用开发框架,可以使用 Vue.js 开发多端应用(如H5、小程序、App等)。在 UniApp 中,可以使用 uni-app 提供的文件系统 API 完成本地文件存储的操作。 1.…...
PyQGIS开发 -- 基础学习笔记
1、自主学习QGIS开发虽然QGIS本身功能强大,但还是架不住我们要编写新的功能、新的业务流程、新的算法。前文中我们提到,扩展QGIS有2种方法,一是用Python、C来写QGIS的插件;另一种就是基于QGIS的C API开发独立应用程序。然而后者资…...
一篇了解模块打包工具之 ——webpack(1)
本篇采用问题引导的方式来学习webpack,借此梳理一下自己对webpack的理解,将所有的知识点连成一条线,形成对webpack的记忆导图。 最终目标,手动构建一个vue项目,目录结构参考vue-cli创建出来的项目 一、问问题 1. 第…...
k8s学习之路 | Day16 k8s 中的容器初探
文章目录容器镜像镜像名称镜像拉取策略私有仓库的拉取策略容器的环境变量和启动命令容器的环境变量容器的启动命令容器的生命周期钩子postStartpreStop容器的探针startupProbelivenessProbereadinessProbek8s 集群中最小的管理单元就是一个Pod,而Pod里面才是容器&am…...
export、import、commit、save、load的区别
目录1. docker export 和 docker import2. docker commit3.docker save 和 docker load1. docker export 和 docker import docker export 容器ID/容器Name > xxx.tar 导出一个容器快照 docker import xxx.tar NewImageName:tag 导入一个容器快照到本地镜像库 适用场景&a…...
多部委联合举办中国人工智能大赛启动会在厦召开,快商通亮相发言
站在“第二个百年奋斗目标”的新起点上,为深入推动我国人工智能产业创新发展,发掘一批人工智能优秀团队, 国家互联网信息办公室、工业和信息化部、公安部、国家广播电视总局、厦门市人民政府将联合主办第四届中国人工智能大赛 。快商通联合创…...
js红宝书学习笔记(1-6章)
就按照原书中写的章节顺序记笔记了, 还有可能我学过js一段时间了,可能有些对于新手的细节会忽略,但是会尽量写全的~ 1.第一章 什么是JavaScript 1.1讲了一些历史,所以我们从1.2开始看 1.2 JavaScript的实现 完整的JaveScript包…...
第十四届蓝桥杯第三期官方模拟赛C\C++题解
文章目录A-填空题题意算法参考代码(C)B-填空题题意算法参考代码(C)C-填空题题意算法参考代码(C)D-填空题题意算法参考代码(C)E-填空题题意算法参考代码(C)F题…...
API接口安全
目前项目都是前后端分离或者有对外提供接口的需求,在这些情况下,就要考虑接口安全。 如果不重视接口安全,可能导致严重的危害,例如数据盗取,服务宕机等。 可能的安全问题: 1.明文密码被攻击者抓包看到 前端可对密码或…...
2023前端一面vue面试题合集
函数式组件优势和原理 函数组件的特点 函数式组件需要在声明组件是指定 functional:true不需要实例化,所以没有this,this通过render函数的第二个参数context来代替没有生命周期钩子函数,不能使用计算属性,watch不能通过$emit 对外暴露事件&…...
【Leetcode 剑指Offer】第 5 天 查找算法(中等)
查找算法剑指 Offer 04. 二维数组中的查找剑指 Offer 11. 旋转数组的最小数字剑指 Offer 50. 第一个只出现一次的字符Python字典基础哈希表(python中是dict())有序哈希表第一个中等,后两个简单题。剑指 Offer 04. 二维数组中的查找 题&#…...
薯条投放适合哪些笔记?小红书薯条投放的3种模式
随着小红书平台的种草推广模式兴盛,薯条投放这个词也渐渐进入大众的视野,今天就来给大家讲讲什么是薯条投放,以及薯条投放适合哪些笔记。一、什么是薯条投放?薯条是一款为小红书用户打造的笔记推广工具,用户可选择推广目标&#…...
记录第一个Python练习的过程
题目如下 编写一个名为collatz()的函数,它有一个名为number的参数。如果参数是偶数,那么collatz()就打印出number // 2,并返回该值。如果number是奇数,collatz()就打印并返回3 * number 1。 然后编写一个程序,让用户…...
【Python】3.3实现多线程
程序Program进程Process线程Thread为完成特定任务而用计算机语言编写的一组计算机能识别和执行的指令的集合。程序是指令、数据及其组织形式的描述,一段静态代码,静态对象。计算机中的程序关于某数据集合上的一次执行过程。进程是程序的实体,…...
在linux中使用lftp和sftp下载文件(夹)
一、首先确保你的系统中已经下载了lftp和sftp。 1.安装lftp sudo apt install lftp sudo apt install screen 2.安装sftp 在Linux系统中,一般RedHat系统默认已经安装了openssh-client和openssh-server,即默认已经集成了sftp服务,不需要重…...
Docker简介与用法
文章目录1、Docker简介1.1、Docker能解决什么问题1.2、什么是虚拟机技术1.2.1、虚拟机的缺点1.3、什么是容器1.3.1、容器与虚拟机比较1.4、分析 Docker 容器架构1.4.1、Docker客户端和服务器1.4.2、Docker 镜像(Image)1.4.3、Docker 容器(Container)1.4.4、Docker 仓库(reposit…...
基于海鸥算法改进的DELM分类-附代码
海鸥算法改进的深度极限学习机DELM的分类 文章目录海鸥算法改进的深度极限学习机DELM的分类1.ELM原理2.深度极限学习机(DELM)原理3.海鸥算法4.海鸥算法改进DELM5.实验结果6.参考文献7.Matlab代码1.ELM原理 ELM基础原理请参考:https://blog.c…...
linux基本功系列之mount命令实战
文章目录前言一. mount命令的介绍二. 语法格式及常用选项三. 参考案例3.1 将iso镜像挂载到/mnt上3.2 把某个分区挂载到/sdb1上3.3 用只读的形式把/dev/sdb2挂载到/sdb2上3.4 设置自动挂载总结前言 大家好,又见面了,我是沐风晓月,本文是专栏【…...
力扣Top100题之两数相加(Java解法)
0 题目描述 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数…...
【测试】Python手机自动化测试库uiautomator2和weditor的详细使用
1.说明 我们之前在电脑操作手机进行自动化测试,基本上都是通过Appium的,这个工具确实强大,搭配谷歌官方的UiAutomator基本上可以完成各种测试,但缺点也很明显,配置环境太麻烦了,需要jdk、sdk等,…...
《NFL橄榄球》:旧金山49人·橄榄1号位
旧金山四九人(San Francisco 49ers,又译旧金山淘金者) 是美国全国橄榄球联盟球队。成立于1946年,最初作为全美橄榄球联合会(AAFC)的一员参加比赛,后于1950年与克利夫兰布朗一同加入由美国橄榄球联合会合并而成的NFL。现任主教练为…...
spark为什么比hadoop快
网上一堆人根本对计算框架一知半解就出来糊弄人,常见解答有: spark是基于内存计算,所以快。这跟废话似的,mr计算的时候不也是基于内存? mr shuffle落盘。这也是胡扯, spark shuffle不落盘? 实际…...
跨境人都在用的指纹浏览器到底有什么魔力?三分钟带你了解透彻
什么是指纹浏览器?这是东哥近期收到最多的粉丝私信咨询,指纹两个字大家都很熟悉,指纹浏览器就变得陌生起来。之前东哥也跟大家分享过很多次指纹浏览器的用法,鉴于还是很多人不认识这个好用的工具,东哥今天就来详细给大…...
机器学习概述
机器学习是人工智能的核心研究领域之一,其研究动机是为了让计算机系统具有人的学习能力以便实现人工智能。目前被广泛采用的机器学习的定义是“利用经验来改善计算机系统自身的性能”。由于“经验在计算机系统中主要是以数据的形式存在的,因此机器学习需…...
企业网站自动生成系统的设计和实现
技术:Java、JSP等摘要:随着Internet技术的发展,人们的日常生活已经离不开网络。未来社会人们的生活和工作将越来越依赖于数字技术的发展,越来越数字化、网络化、电子化、虚拟化。Internet的发展历程以及目前的应用状况和发展趋势&…...
sikuli+eclipse对于安卓app自动化测试的应用
Sikuli是什么? 下面是来自于官网的介绍:Sikuli is a visual technology to automate and test graphical user interfaces (GUI) using images (screenshots). Sikuli includes Sikuli Script, a visual scripting API for Jython, and Sikuli IDE, an …...
react源码分析:babel如何解析jsx
同作为MVVM框架,React相比于Vue来讲,上手更需要JavaScript功底深厚一些,本系列将阅读React相关源码,从jsx -> VDom -> RDOM等一些列的过程,将会在本系列中一一讲解 工欲善其事,必先利其器 经过多年的…...
搜广推 WideDeep 与 DeepCrossNetwork (DCN) - 记忆+泛化共存
😄 这节来讲讲Wide&Deep与Deep&CrossNetwork (DCN)。从下图可看出WD非常重要,后面衍生出了一堆WD的变体。本节要讲的WD和DCN结构都非常简单,但其设计思想值得学习。 🚀 wide&deep:2016年,谷歌提出。 🚀 Deep&CrossNetwork (DCN):2017年,谷歌和斯坦…...
项目管理工具dhtmlxGantt甘特图入门教程(十四):导出/导入 Excel到 iCal
这篇文章给大家讲解利用dhtmlxgantt导入/导出Excel到iCal的操作方法。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表,可满足应用程序的所有需求,是完善的甘特图图表库 DhtmlxGantt正版试用下载(qun;765665…...
k-means聚类总结
1.概述 聚类算法又叫做‘无监督学习’,其目的是将数据划分成有意义或有用的组(或簇)。 2.KMeans 关键概念:簇与质心 KMeans算法将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的…...
做网站需要注意什么问题/新闻式软文
C语言程序设计(第七章 指针) 一、指针是什么 由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化地称为“指针”。意思就是通过它能找到以它为地址的内存单元。 假如有输入语句&#…...
新手怎样在手机上做电商/seo服务方案
(《partner4java 讲述jBPM4》仅为技术储备 -- 本人并没有jBPM4实战方面丰富的经验;学习本内容最好有Hibernate的基础) 代码下载地址:文章中贴出的代码可能有所改动,以下载地址为准http://download.csdn.net/detail/pa…...
查网站跳出率/淘宝代运营公司
标签: 烟波钓叟歌概述讲解 《烟波钓叟赋》 宋初有长诗一篇,言遁甲术,盖北宋通人所作。后经明朝罗通增删修改,更名《烟波钓叟歌》。罗通江西吉水人,永乐十年进士,善用兵,宣德、正统、景泰年间,屡…...
b2b网站论文/今日足球赛事推荐
以下是全部VolleyError实例可能,如果需要逐条判断可以方便用户了解原因。 //正如前面代码看到的,在创建一个请求时,需要添加一个错误监听onErrorResponse。如果请求发生异常,会返回一个VolleyError实例。 //以下是Volley的异常列…...
用bootstrap做的网站有哪些/免费域名注册永久
题目 题目非常简单,无非就是判断一个没用头结点的指针,是否为回文链表,但是简单的题目往往值得更深的思考。该题目有很多的解法,想要在时间击败百分百的话,不仅仅是代码本身,可能跟电脑还有一定的关系。 全…...
做网站价位/电脑全自动挂机赚钱
几种并发服务器模型的实现:多线程,多进程,select,poll,epoll - rail 时间 2014-07-31 00:18:00 博客园-所有随笔区原文 http://www.cnblogs.com/wj9012/p/3879605.html主题 Socket 多线程 Epoll#include <stdio.h&…...