WPF中手写地图控件(4)——离线地图

内存缓存和本地文件缓存技术

如果每个瓦片图每次打开都要重新加载,会比较浪费资源,而且如果网络不好,甚至要等很久,于是可以使用内存缓存,每次已经加载的瓦片图,第二次再加载之前,先看看内存中有没有,这就是内存缓存技术。但是软件已关闭,内存数据全部清空了,下次再打开,又要重新加载,比较浪费资源,于是可以使用本地文件缓存技术,也就是离线地图。

/// <summary>
/// 缓存管理
/// </summary>
internal class CacheManager : IDisposable
{/// <summary>/// 默认缓存一个G/// </summary>public int MemoryMaxCacheSize = 1000000;/// <summary>/// 当前已经使用的内存缓存大小/// </summary>public long CurrentMemoryCacheSize = 0;/// <summary>/// 缓存/// </summary>private HashSet<string> LocalCache = new HashSet<string>();/// <summary>/// 内存缓存/// </summary>private IntPtr MemoryCache = IntPtr.Zero;/// <summary>/// 是否已经释放/// </summary>private bool isDisposed = false;/// <summary>/// 内存缓存数据缓存区域/// </summary>private Dictionary<string, MemoryRange> MemoryCacheDataRange = new Dictionary<string, MemoryRange>();/// <summary>/// 缓存文件夹/// </summary>public string CacheFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "map_caches");/// <summary>/// 是否开启本地文件缓存/// </summary>private bool IsOpenLocalCache = true;/// <summary>/// 是否开启内存缓存/// </summary>private bool IsOpenMemoryCache = true;/// <summary>/// 内存缓存是否已经满了/// </summary>private bool IsMemoryFull = false;/// <summary>/// 锁/// </summary>private object MemoryLocked = new object();private object LocalLocked = new object();/// <summary>/// 构造函数/// </summary>/// <param name="size">内存缓存大小</param>/// <param name="unit">内存缓存单位</param>/// <param name="isOpenLocalCache">是否开启文件缓存</param>/// <param name="isOpenMemoryCache">是否开启内存缓存</param>public CacheManager(int size, MemorySizeUnit unit, bool isOpenLocalCache, bool isOpenMemoryCache){switch (unit){case MemorySizeUnit.GB:MemoryMaxCacheSize = size * 1024 * 1024 * 1024;break;case MemorySizeUnit.MB:MemoryMaxCacheSize = size * 1024 * 1024;break;case MemorySizeUnit.KB:MemoryMaxCacheSize = size * 1024;break;default:break;}IsOpenLocalCache = isOpenLocalCache;IsOpenMemoryCache = isOpenMemoryCache;MemoryCache = Marshal.AllocHGlobal(MemoryMaxCacheSize);InitCacheMode();}/// <summary>/// 析构函数/// </summary>~CacheManager(){Dispose(false);}/// <summary>/// 初始化缓存模型/// </summary>public void InitCacheMode(){if (IsOpenLocalCache){Debug.WriteLine("地图开启缓存模式...");// 如果开启缓存模式if (!Directory.Exists(CacheFolder)){Directory.CreateDirectory(CacheFolder);}var dirs = Directory.GetDirectories(CacheFolder);foreach (var dir in dirs){foreach (var file in Directory.GetFiles(dir)){LocalCache.Add(file);}}}}/// <summary>/// 读取或者添加一个内存缓存/// </summary>/// <param name="name"></param>/// <param name="memoryData"></param>/// <param name="size"></param>/// <returns></returns>public unsafe (MemoryRange, bool) ReadOrSetFromMemoryCache(string name, System.Drawing.Bitmap map = null){lock (MemoryLocked){if (map == null){MemoryRange memory = null;MemoryCacheDataRange.TryGetValue(name, out memory);return (memory, true);}else{if(IsMemoryFull){return (null, false);}var size = map.Width * map.Height * 3;if(CurrentMemoryCacheSize + size > MemoryMaxCacheSize){IsMemoryFull = true;return (null, false);}var range = new MemoryRange(CurrentMemoryCacheSize, CurrentMemoryCacheSize + size, MemoryCache + (int)CurrentMemoryCacheSize);var mapData = map.LockBits(new System.Drawing.Rectangle(new System.Drawing.Point(), map.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);Buffer.MemoryCopy(mapData.Scan0.ToPointer(), range.Address.ToPointer(), range.Length, (int)range.Length);map.UnlockBits(mapData);MemoryCacheDataRange.Add(name, range);CurrentMemoryCacheSize += size;return (range, true);}}}/// <summary>/// 读取或者添加一个文件缓存/// </summary>/// <param name="name"></param>/// <param name="memoryData"></param>/// <param name="size"></param>/// <returns></returns>public bool ReadOrSetFromLocalCache(string name, bool isGet){lock (LocalLocked){if (isGet){if (LocalCache.Contains(name)){return true;}return false;}else{// 如果已经存在本地了 则不需要重新添加if (LocalCache.Contains(name))return false;LocalCache.Add(name);return true;}}}/// <summary>/// 获取缓存文件路径/// </summary>/// <param name="block"></param>/// <returns></returns>private string GetCacheFilePath(TitleBlock titleBlock){var dir = Path.Combine(CacheFolder, titleBlock.Level.ToString());if (Directory.Exists(dir) is false) Directory.CreateDirectory(dir);var fileName = string.Format("{0}\\{1}", dir, titleBlock.ToCacheFileName());return fileName;}/// <summary>/// 读取数据/// </summary>/// <param name="block"></param>/// <returns></returns>public async Task<MemoryRange> ReadTitleData(TitleBlock block){MemoryRange address = null;string memoryCacheName = block.ToCacheKey();   //内存缓存名称string localCacheName = GetCacheFilePath(block); //本地文件缓存名称if (IsOpenMemoryCache){address = ReadOrSetFromMemoryCache(memoryCacheName).Item1;}// 如果从内存中直接读取出来则直接返回if (address != null) return address;System.Drawing.Bitmap bitmap = null;// 如果 开启了文本本地缓存,并且文件确实在本地有缓存if (IsOpenLocalCache && ReadOrSetFromLocalCache(localCacheName, true)){// 从文件中读取数据bitmap = ReadDataFromLocalFile(localCacheName);}// 如果文件中不存在 进行下载if(bitmap == null){bitmap = await ReadDatasFromHttp(block.Url, localCacheName);}// 存入内存if (bitmap != null && IsOpenMemoryCache){// 存入内存var res = ReadOrSetFromMemoryCache(memoryCacheName, bitmap);// 如果保存成功了if (res.Item2){address = res.Item1;bitmap.Dispose();}else{address = new MemoryRange(0, bitmap.Width * 3 * bitmap.Height, IntPtr.Zero) { Bitmap = bitmap };}}// 如果获取到图片并且不需要内存缓存则直接使用else if (bitmap != null && !IsOpenMemoryCache && address == null){address = new MemoryRange(0, bitmap.Width * 3 * bitmap.Height, IntPtr.Zero) { Bitmap = bitmap };}return address;}/// <summary>/// 转换位图/// </summary>/// <param name="jpegDatas"></param>/// <param name="isSaveToLocal"></param>/// <param name="localPath"></param>/// <returns></returns>private System.Drawing.Bitmap ConvertToBmpDatas(MemoryStream jpegDatas, bool isSaveToLocal, string localPath){System.Drawing.Bitmap jpeg = System.Drawing.Image.FromStream(jpegDatas) as System.Drawing.Bitmap;if (isSaveToLocal){jpeg.Save(localPath, System.Drawing.Imaging.ImageFormat.Bmp);}return jpeg;}/// <summary>/// 从http中读取数据/// </summary>/// <param name="url"></param>/// <param name="localCacheName"></param>/// <returns></returns>private async Task<System.Drawing.Bitmap> ReadDatasFromHttp(Uri url, string localCacheName){System.Drawing.Bitmap bitmap = null;int tryTimes = 10;using (HttpClient Client = new HttpClient()){while (tryTimes-- > 0 && bitmap == null){try{var res = await Client.GetAsync(url);if (res.StatusCode == System.Net.HttpStatusCode.OK){var stream = await res.Content.ReadAsStreamAsync() as MemoryStream;// 读取数据并且检测是否保存到本地文件bitmap = ConvertToBmpDatas(stream, IsOpenLocalCache, localCacheName);// 添加一个本地的文件缓存信息if (IsOpenLocalCache){ReadOrSetFromLocalCache(localCacheName, false);}if (bitmap != null) return bitmap;}}catch (Exception ex) { }}}return bitmap;}/// <summary>/// 从本地文件缓存中加载数据/// </summary>/// <param name="localCacheName">本地缓存文件名称</param>/// <returns></returns>private Bitmap ReadDataFromLocalFile(string localCacheName){try{var bitmap = new System.Drawing.Bitmap(localCacheName);if (bitmap == null || bitmap.Width == 0 || bitmap.Height == 0){if (bitmap != null) bitmap.Dispose();bitmap = null;}return bitmap;}catch (Exception ex){return null;}}/// <summary>/// 释放/// </summary>public void Dispose(){Dispose(true);}public void Dispose(bool dispose){if (isDisposed){return;}if (dispose){//  释放托管的 IDispose 对象}// 释放非托管内容Marshal.FreeHGlobal(MemoryCache);isDisposed = true;}
}

获取瓦片的时候

/// <summary>
/// 读取数据
/// </summary>
/// <returns></returns>
public Task<MemoryRange> ReadStream() => CacheManager.ReadTitleData(this);

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

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

相关文章

ARM开发(cortex-A7核中断实验)

1.实验目的&#xff1a;实现KEY1/LEY2/KE3三个按键&#xff0c;中断触发打印一句话&#xff0c;并且灯的状态取反&#xff1b; key1 ----> LED3灯状态取反&#xff1b; key2 ----> LED2灯状态取反&#xff1b; key3 ----> LED1灯状态取反&#xff1b; 2.分析框图: …

IDEA快速设置Services窗口

现在微服务下面会有很多SpringBoot服务&#xff0c;Services窗口方便我们管理各个SpringBoot服务&#xff0c;但有时IDEA打开项目后无法的看到Services窗口&#xff0c;以下步骤可以解决&#xff01;

leetcode 151. 反转字符串中的单词

反转字符串中的单词 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输入字符串 s中可能…

Windows环境使用bat脚本启动Java服务

Java项目一般会被打包成jar后启动&#xff0c;在windows系统中可以通过终端窗口cmd启动jar包&#xff0c;即在jar包所在的目录中打开cmd&#xff0c;或在cmd中进入到jar包目录&#xff0c;执行如下命令&#xff1a; java -jar test.jar 在bat脚本中执行java服务&#xff0c;命…

西瓜书之神经网络

一&#xff0c;神经元模型 所谓神经网络&#xff0c; 目前用得最广泛的一个定义是“神经网络是由具有适应性的简单单元组成的广泛并行互连的网络&#xff0c;它的组织能够模拟生物神经系统对真实世界物体所做出的交互反应”。 M-P神经元 M-P神经元&#xff1a;接收n个输入(…

Nodejs-nrm:快速切换npm源 / npm官方源和其他自定义源之间切换

一、理解 Nodejs nrm Nodejs nrm 是一个管理 npm 源的工具。由于 npm 在国内的速度较慢&#xff0c;很多开发者会使用淘宝的 npm 镜像源&#xff0c;但是也会遇到一些问题&#xff0c;例如某些包在淘宝镜像源中不存在&#xff0c;或者淘宝镜像源本身也会有问题。 Nodejs nrm …

计算机竞赛 基于CNN实现谣言检测 - python 深度学习 机器学习

文章目录 1 前言1.1 背景 2 数据集3 实现过程4 CNN网络实现5 模型训练部分6 模型评估7 预测结果8 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于CNN实现谣言检测 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&am…

JavaScript中的设计模式之一--单例模式和模块

虽然有一种疯狂天才的感觉可能很诱人&#xff0c;但重新发明轮子通常不是设计软件的最佳方法。很有可能有人已经遇到了和你一样的问题&#xff0c;并以一种聪明的方式解决了它。这样的最佳实践在形式化后被称为设计模式。今天我们来看看它们的概念&#xff0c;并检查单例模式和…

AWS解决方案日:Web 3业务安全方案

近日&#xff0c;AWS合作伙伴之Web3解决方案日在香港举办&#xff0c;多家科技公司专家和企业代表就WEB 3.0方案、AI创新和Web 3.0安全进行了探讨。顶象现场展示了Web 3.0业务安全解决方案。 NFT是Web 3.0典型场景之一。NFT基于区块链技术的非同质化代币&#xff0c;具有不可分…

Java入坑之 数据库编程

一、基础概念 1.1JDBC 步骤 导入驱动jar包 注册驱动 获取数据库连接对象 Connection DataSource dSource; dSource.getConnection(); 定义sql语句 String sql "update account set balance 500 where id 1"; 获取执行sql语句的对象 Statement PreparedStatement…

在mac下,使用Docker安装达梦数据库

前言&#xff1a;因为业务需要安装达梦数据库 获取官网下载tar包&#xff08;达梦官网的下载页面https://www.dameng.com/list_103.html&#xff09;&#xff0c;或者通过命令 一、下载tar包 命令下载&#xff1a;wget -O dm8_docker.tar -c https://download.dameng.com/eco/…

实战:大数据Spark简介与docker-compose搭建独立集群

文章目录 前言技术积累Spark简介Spark核心功能及优势Spark运行架构 Spark独立集群搭建安装docker和docker-composedocker-compose编排docker-compose编排并运行容器 Spark集群官方案例测试写在最后 前言 很多同学都使用过经典的大数据分布式计算框架hadoop&#xff0c;其分布式…

学Python静不下来,看了一堆资料还是很迷茫是为什么

一、前言 最近发现&#xff0c;身边很多的小伙伴学Python都会遇到一个问题&#xff0c;就是资料也看了很多&#xff0c;也花了很多时间去学习但还是很迷茫&#xff0c;时间长了又发现之前学的知识点很多都忘了&#xff0c;都萌生出了想半路放弃的想法。 让我们看看蚂蚁金服的大…

Apache zookeeper kafka 开启SASL安全认证 —— 筑梦之路

简介 Kafka是一个高吞吐量、分布式的发布-订阅消息系统。Kafka核心模块使用Scala语言开发&#xff0c;支持多语言&#xff08;如Java、Python、Go等&#xff09;客户端&#xff0c;它可以水平扩展和具有高吞吐量特性而被广泛使用&#xff0c;并与多类开源分布式处理系统进行集成…

双目视觉之-棋盘格标定板制作

棋盘格设计地址&#xff1a; https://markhedleyjones.com/projects/calibration-checkerboard-collection 包括A0&#xff0c;A1&#xff0c;A2&#xff0c;A3和A4多种规格的棋盘格标定板&#xff0c;支持自定义设置棋盘格grid宽度和高度。 基于Matlab的双目视觉标定流程和O…

通过微软Azure调用GPT的接口API-兼容平替OpenAI官方的注意事项

众所周知&#xff0c;我们是访问不通OpenAI官方服务的&#xff0c;但是我们可以自己通过代理或者使用第三方代理访问接口 现在新出台的规定禁止使用境外的AI大模型接口对境内客户使用&#xff0c;所以我们需要使用国内的大模型接口 国内的效果真的很差&#xff0c;现在如果想使…

什么是卷积神经网络

目录 什么是卷积神经网络 全链接相对笨重&#xff1a;大胖子​编辑 ​编辑 参数众多&#xff1a;容易造成过拟合 ​编辑 卷积核&#xff1a;进行图像特征提取&#xff0c;源于卷积原理&#xff1a;求相交面积 卷积的作用 卷积的意义 ​编辑 通过卷积核减少参数 深度卷积…

聊聊springboot tomcat的maxHttpFormPostSize

序 本文主要研究一下spring boot tomcat的maxHttpFormPostSize参数 parseParameters tomcat-embed-core-9.0.37-sources.jar!/org/apache/catalina/connector/Request.java /*** Parse request parameters.*/protected void parseParameters() {parametersParsed true;Para…

Python基础(十六)——Lambda 表达式

目录 1、Lambda 表达式是什么2、和def所定义的python函数的区别3、Lambda 表达式的定义3、Lambda 表达式的特点4、Lambda 表达式中用三目运算语句5、lambda的参数形式5.1、Lambda 表达式直接调用。5.2、无参数5.3、一个参数5.3、默认参数5.4、可变参数&#xff1a;**args5.5、可…

微信小程序教学系列(4)

微信小程序教学系列 第四章&#xff1a;小程序优化与调试 1. 性能优化技巧 在开发微信小程序时&#xff0c;我们可以采取一些性能优化技巧&#xff0c;以提升小程序的性能表现和用户体验。以下是一些常用的性能优化技巧&#xff1a; 减少网络请求&#xff1a;尽量合并网络请…