遍历文件夹更新JSON文件内容

遍历文件夹更新 JSON 文件内容 最近,有一个需求,需要从根目录下查找子文件夹,如果子文件夹下的文件是.md 后缀,并且在原始的 data.json 数据中存在,则取出来生成新的对象。然后存入到 data-temp.json 文件中。 使用 Python 实现的,真的很方便。如果自己复制粘贴,需要好长时间,但是使用脚本一秒就够了。 import os import json import re from typing import List, Dict # 固定路径配置 SCAN_DIR = "扫描目录" JSON_FILE = "原始JSON数据文件" OUTPUT_FILE = "存入JSON数据文件" def is_valid_folder(folder_name: str) -> bool: """检查文件夹名是否不包含数字""" return not bool(re.search(r'\d', folder_name)) def find_matching_files() -> List[Dict]: """ 查询指定目录下的子文件夹(排除含数字的),查找.md文件,并从JSON文件中查找匹配的记录 """ # 读取并预先加载JSON文件 try: print(f"正在加载JSON文件: {JSON_FILE}") with open(JSON_FILE, 'r', encoding='utf-8') as f: json_data = json.load(f) # 创建以id为键的字典提高查询效率 id_map = {str(item.get('id')): item for item in json_data if isinstance(item, dict) and 'id' in item} print(f"成功加载 {len(id_map)} 条JSON记录") except FileNotFoundError: print(f"错误:JSON文件 {JSON_FILE} 未找到") return [] except json.JSONDecodeError: print(f"错误:JSON文件 {JSON_FILE} 格式不正确") return [] except Exception as e: print(f"加载JSON数据时出错: {e}") return [] results = [] valid_folders = [] print(f"\n开始扫描目录: {SCAN_DIR}") # 遍历根目录下的所有子文件夹 for category in os.listdir(SCAN_DIR): # 跳过包含数字的文件夹 if not is_valid_folder(category): continue subdir_path = os.path.join(SCAN_DIR, category) # 确保是目录 if not os.path.isdir(subdir_path): continue valid_folders.append(category) print(f"发现有效分类目录: {category}") # 遍历子目录中的.md文件 for filename in os.listdir(subdir_path): # 只处理.md文件 if not filename.endswith('.md'): continue # 使用完整的文件名(保留.md后缀)作为ID file_id = filename # 在预先加载的JSON数据中查找匹配的ID if file_id in id_map: item = id_map[file_id] # 创建记录 record = { 'id': item.get('id'), 'name': item.get('name', ''), 'category': category, 'kw': '', 'plat': 'mp', 'filename': filename } results.append(record) print(f"匹配成功: {category}/{filename} -> ID {item.get('id')}") # 打印扫描摘要 print("\n扫描完成,结果摘要:") print(f" - 有效分类目录: {len(valid_folders)} 个") print(f" - 匹配到的文件: {len(results)} 个") return results def save_to_json(data: List[Dict]) -> bool: """ 将数据保存为JSON文件 """ try: with open(OUTPUT_FILE, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"\n结果已保存到: {OUTPUT_FILE}") return True except Exception as e: print(f"\n保存文件时出错: {e}") return False if __name__ == "__main__": # 获取匹配结果 matched_records = find_matching_files() # 保存结果 if save_to_json(matched_records): print("操作成功完成") else: print("操作完成,但保存结果时出现问题") 可以以此为模板,碰到合适场景可以直接使用。

2026-01-05 · 2 min · Eagle

处理Excel文件获取IP网段

处理 Excel 文件获取 IP 网段 我获取了一份有 IP 网段的 Excel 表,这些 IP 网络段是用来在登录后台时判断 IP 是否允许时使用。 Excel 表的格式如下: 起始号段 结束号段 1.192.0.0 1.192.7.255 1.192.16.0 1.192.71.255 我现在需要处理这个 Excel,将其中的 IP 地址转换为数字形式,并生成适合导入 MySQL 的 CSV 格式数据。 现在是使用 Python 进行处理。需要安装 pandas,使用 pip 安装pip install pandas。IP 地址转换为整数时使用的是无符号 32 位整数表示。 脚本代码如下: import pandas as pd import ipaddress # 1. 读取Excel文件(请将'ip_ranges.xlsx'替换为您的实际文件名) excel_file = 'ip_ranges.xlsx' df = pd.read_excel(excel_file) # 2. 定义IP地址转数字的函数 def ip_to_int(ip_str): """将IP地址字符串转换为整数""" return int(ipaddress.ip_address(ip_str)) # 3. 转换IP地址为数字 df['起始数字'] = df['起始号段'].apply(ip_to_int) df['结束数字'] = df['结束号段'].apply(ip_to_int) # 4. 生成输出结果 output_lines = [] for _, row in df.iterrows(): line = f"{row['起始数字']},{row['结束数字']}" output_lines.append(line) # 5. 打印转换结果 print("IP地址范围转换为数字后的结果:") for line in output_lines: print(line) # 6. 保存为CSV文件(可直接导入MySQL) output_csv = 'ip_ranges_converted.csv' df[['起始数字', '结束数字']].to_csv(output_csv, index=False, header=False) print(f"\n转换结果已保存到 {output_csv} 文件,可直接导入MySQL。") 将这段代码保存为一个.py 文件,例如 ip_converter.py。然后将 Excel 文件和脚本保存在同一个目录,然后运行脚本即可。

2026-01-05 · 1 min · Eagle

从按钮开始:组件的属性与事件绑定

从按钮开始:组件的属性与事件绑定 我们通过按钮来举例,它就是一个组件,在微信小程序开发中,组件是构建用户界面的基本单元。本文将以 button 组件为例,介绍组件的属性与事件绑定,并通过一个点击弹窗的示例对比代码与预览效果。 目录 组件的基本属性 事件绑定 实现点击弹窗 代码与预览效果对比 组件的基本属性 微信小程序的 button 组件有多个属性,如 type、size、plain、disabled 等,用于控制按钮的样式和行为。 示例代码 <!-- button.wxml --> <view class="container"> <!-- 默认按钮 --> <button>默认按钮</button> <!-- 主按钮 --> <button type="primary">主按钮</button> <!-- 警告按钮 --> <button type="warn">警告按钮</button> <!-- 禁用按钮 --> <button disabled>禁用按钮</button> </view> 事件绑定 微信小程序的组件可以通过 bind 或 catch 前缀绑定事件处理函数。常见的事件有点击事件、长按事件等。 示例代码 <!-- button.wxml --> <view class="container"> <button bindtap="handleTap">点击我</button> </view> // button.js Page({ handleTap: function () { wx.showToast({ title: "按钮被点击", icon: "success", duration: 2000, }); }, }); 实现点击弹窗 接下来,我们通过一个完整的示例实现点击按钮弹出弹窗,并展示代码与预览效果对比。 ...

2026-01-05 · 2 min · Eagle

豆子碎片的故事

豆子碎片的故事 豆子碎片小程序很早就注册了,刚开始做的功能就是浏览 Go Web 框架 Beego 的教程。当时,正在自学 Beego,而 Beego 的网站时常打不开,就想做一个小程序,可以浏览 Beego 内容。当时看到了 towxml 组件,正好可以实现 Markdown 转 Wxml,于是就将 Beego 的 内容文档写成 Markdown 格式,做成了小程序。小程序的项目名叫 visit,就是浏览的意思。 当时小程序还是使用的云环境,云环境免费,并提供 dev 和 pro 两个环境。将 Beego 的 Markdown 文件存在云存储中。使用云函数调用数据。在小程序端使用 towxml 解析 Markdown 数据。当时发布小程序后,还是很受欢迎的。 中间歇了一段时间,没有更新文章,也没有维护小程序,小程序日浏览人数就下降了。云环境收费后,就彻底不管了。 后来,买了一台云服务器,为了练习自己所学的 Golang 语言,就将小程序重新拾起来。新做的项目内容是浏览唐诗,使用 Gin 框架进行后端开发,小程序端的布局和现在的豆子碎片布局差不多,只有一个首页,首页包含标题、一个搜索框、几个快捷按钮。项目很快完成,将小学和初中的唐诗、宋词、古诗经都录入了数据库,维护了很长一段时间。小程序上线后,每天也有几个人访问。在录入高中的唐诗内容时,就无法坚持下去了,高中的唐诗等内容都比较长,页面排版非常不美,所以高中的内容就没有录入。小程序在展示唐诗内容时,刚开始使用 Markdown 展示。后来想添加拼音,就将 Markdown 去掉,手撸 wxml,最后,拼音也添加了,但是费了很大劲,自己不擅长前端,美工。本还计划添加录音,但实在没有素材,真正做起来,费时费力,没有精力和动力就搁置了。 2024 年微信平台要求小程序都要备案。我有三个小程序,本想都放弃了,但后来,在工作中要用到音频格式转换,在小程序端实现操作起来是真的很方便,省时省力,不需要开电脑,也可以在任何时间操作。所以计划留下一两个吧。在备案的时候,注销了一个,剩下了两个,目前还在使用和维护,一个是豆子工具,用来制作工具,平时我也在用,一个是豆子碎片,记录技术经验和代码片段。在备案豆子碎片小程序时,小程序原名称叫找唐诗,提交备案后,微信备案客服人员说唐诗这两字不让用,让换个名称。在换名称的时候,我就在想这个小程序要不要放弃?不放弃做什么内容?已经有一个豆子工具小程序做工具了,没有必要再做一个工具类小程序吧。一直没有想好,等微信备案人员二次打电话时(真的很负责),才确定下来,做笔记类应用,记录日常开发经验和技巧以及代码片段,本想叫代码碎片,为了和豆子工具保持一致,小程序名称就叫豆子碎片,寓意像玩积木一样,学了本小程序内容,你也可以制作一款你想要的小程序。 豆子碎片项目已经开源,项目地址:https://github.com/littletow/visit 豆子碎片目前没有实名认证,如果你喜欢就收藏一下。豆子碎片面对的人群是有技术门槛的,后续看情况再进行实名认证。 豆子碎片的文章也已经在我公众号发布。有兴趣可以查看一下,一个程序员之小程序的成长与蜕变 想要查看豆子碎片,可以扫下面的小程序码:

2026-01-05 · 1 min · Eagle

豆子碎片内部逻辑

豆子碎片内部逻辑 虽然项目已经完成,但是温故而知新。我们梳理一下。结合以前学到的基础知识。我们进行总结。 APP 启动操作流程如下: APP 启动,加载设备信息,若没有则进行获取并缓存到系统,加载最新版本检查时间,若没有则下载版本文件,下载数据文件,然后缓存版本检查时间;若有,则和今天零时对比,若大于零时时间,则表示已经更新,从缓存中直接加载数据,若小于零时时间,则表示还未更新,从服务器下载版本文件,然后和本地的版本进行对比。如线上更新,则更新数据文件,并同步本地版本。然后将数据保存在文件系统中。如果没有更新,直接从文件系统中获取数据,然后存储到 app 的 artList 对象中。 界面渲染完毕后,会显示首页,首页和用户交互的有搜索框和分类按钮。 当使用搜索框搜索时,根据填写的内容作为关键字在 artList 列表中进行查询,查询步骤顺序,先查询标题,如果标题包含直接返回,然后查询关键词,如果包含直接返回,最后查询标签,如果包含直接返回。最后组成列表并进行分页,返回数据给页面。页面将跳转到列表页面,并渲染列表。列表中的每一项都可以点击,点击之后就进入到文章页。 文章页的功能将文章 Markdown 数据下载到本地,然后使用 towxml 插件将数据渲染并显示。 分类按钮是按照项目来分类,当点击按钮时,从文章索引列表中将相关的项目分类数据提取组成列表,分页之后返回给页面。

2026-01-05 · 1 min · Eagle

豆子碎片小程序开发实践:从核心功能到技术实现

豆子碎片小程序开发实践:从核心功能到技术实现 前面介绍了如何学习豆子碎片小程序,今天本文将介绍包括核心功能实现、技术方案对比和业务逻辑落地等方面。豆子碎片小程序是一款小程序技术和经验等内容展示类的小程序,主要用于展示 Markdown 文件解析后的内容。 核心功能实现 豆子碎片小程序的核心功能主要包括以下几个方面: 数据下载与本地缓存:每次小程序启动时,从服务器下载最新的 Markdown 文件,并缓存到本地,以便后续使用。 Markdown 解析与渲染:使用 towxml 组件解析下载的 Markdown 文件,并渲染成 wxml 文件,以便在小程序中展示。 首页布局与搜索:首页采用上中下布局,上方介绍小程序的用途,中间是搜索框,下方是快捷按钮。当用户在搜索框输入内容或点击快捷按钮时,查询出相关的文章列表。 文章详情展示:点击文章列表中的文章,跳转到文章详情页,展示文章的详细内容。 技术方案对比 在实现豆子碎片小程序的过程中,我们对多种技术方案进行了对比,最终选择了以下技术方案: 数据下载与本地缓存 方案一:每次启动时都从服务器下载数据:这种方案实现简单,但会增加网络请求次数,影响小程序的启动速度和用户体验。 方案二:使用本地缓存:在小程序启动时,先检查本地缓存是否有最新数据,如果有则直接使用,否则从服务器下载数据并缓存到本地。最终我们选择了这种方案,以提高小程序的启动速度和用户体验。 Markdown 解析与渲染 方案一:自定义解析器:自行开发 Markdown 解析器,解析 Markdown 文件并生成 wxml 文件。这种方案实现复杂,维护成本高。 方案二:使用现有组件:我们对比了 wxParse 组件和 towxml 组件,最终选择使用开源的 towxml 组件进行 Markdown 解析和渲染,它组件成熟,易于集成和使用。最终我们选择了这种方案,以简化开发流程并提高开发效率。 首页布局与搜索 方案一:手动实现布局和搜索功能:自行编写代码实现首页布局和搜索功能,灵活性高,但开发成本较高。 方案二:使用微信小程序提供的组件:使用微信小程序提供的 UI 组件,如<view>、<input>、<button>等,实现首页布局和搜索功能,并使用 weui 样式。最终我们选择了这种方案,以简化开发工作并提高开发效率。 业务逻辑落地 下方只展示了代码片段,详情请查看 visit 项目。 数据下载与本地缓存 在小程序的 app.js 文件中,我们实现了数据下载和本地缓存的逻辑: // 登入 async login() { const that = this; const tzms = utils.getTodayZeroMsTime(); // 获取今日零时毫秒时间戳 // 检查设备信息? that.logDevInfo(); // 检查Git服务是否正常? const isAlive = await that.chkServerAlive(); console.log('url,', that.globalData.url, isAlive); // 检查版本更新? that.uptVer(tzms); // 加载用户信息 that.onLogin(); }, // 小程序每次启动都会调用 onLaunch: function () { const startTime = Date.now(); this.globalData.startTime = startTime; this.login(); const loginTime = Date.now(); const launchTime = loginTime - startTime; console.log(`app onLaunch: ${launchTime} ms`); }, 首页布局与搜索 在首页的 index.wxml 文件中,我们实现了上中下布局和搜索框: ...

2026-01-05 · 3 min · Eagle

将JSON文件转换为Protobuf格式

将 JSON 文件转换为 Protobuf 格式 当完成 JSON 文件后,我们需要将它转换为 Protobuf 格式,使用这种格式,可以更高效的存储和传输文件。它特别适合大数据的场景。 现在通过 Python 将 JSON 文件转换为 Protobuf 格式。 1,定义 Protobuf 结构,创建一个.proto 文件(如 data.proto)来定义数据结构: syntax = "proto3"; message DataItem { string id = 1; string name = 2; string kw = 3; bool lock = 4; string category = 5; string label = 6; int32 grade = 7; // 新添加的字段 } message DataList { repeated DataItem items = 1; } 2,生成 Python 代码,安装 Protobuf 编译器并生成代码: ...

2026-01-05 · 2 min · Eagle

将数组按照时间重新降序排序

将数组按照时间重新降序排序 在写笔记列表页面时,发现从服务器获取的笔记列表包含最新更新时间 lastts,当我们想将最新更新的条目展示在最上端时,我们需要排序数组,将数组按照时间重新排序,排序规则为最新的时间条目放在最前面。 这样我们就可以在笔记列表中让用户看到最新更新的内容了。 我们需要将其封装为函数,方便调用。 函数代码如下: // 按照更新时间排序的函数 sortNotesByLastTs: function(notes) { return notes.slice().sort((a, b) => { // 将时间字符串转为时间戳比较 const timeA = new Date(a.lastts).getTime(); const timeB = new Date(b.lastts).getTime(); // 降序排列(最新的在前) return timeB - timeA; }); }, 当运行之后,发现时间戳格式和服务器返回格式不一致,我们需要重新调整函数,服务器返回格式 YYYY-MM-DD HH:mm:ss,本地函数使用的时间格式 ISO 8601 格式。 调整后的代码如下: // 按照更新时间排序的函数(适配"YYYY-MM-DD HH:mm:ss"格式) sortNotesByLastTs: function(notes) { return notes.slice().sort((a, b) => { // 解析自定义时间格式 const parseTime = (timeStr) => { if (!timeStr) return 0; // 替换空格为T,使其符合ISO格式 const isoFormat = timeStr.replace(' ', 'T'); return new Date(isoFormat).getTime() || 0; }; const timeA = parseTime(a.lastts); const timeB = parseTime(b.lastts); // 降序排列(最新的在前) return timeB - timeA; }); }, 推荐还是调整服务器端,让返回的时间格式转为 ISO 8601 格式。

2026-01-05 · 1 min · Eagle

将字符串转为数组

将字符串转为数组 上次,我们看到标签是数组,但是从服务器下载的原始文件是字符串,多个标签以逗号分割,所以我们需要转换,将字符串转为数组。 转换逻辑也非常简单,将字符串以逗号分割转换为数组,然后复制给 tags 属性。 我们将其封装为一个函数,方便调用。 处理函数如下: // 将标签字符串转换为数组的函数 convertTagsStrToArray: function(tagsStr) { if (!tagsStr || typeof tagsStr !== 'string') { return []; } // 分割字符串并去除前后空格 return tagsStr.split(',') .map(tag => tag.trim()) .filter(tag => tag.length > 0); // 过滤掉空标签 }, 当接收到标签字符串后,先判断字符串是否为空,或者不是字符串类型,然后使用了 Js 的 split 函数按逗号分割字符串,然后使用 map 函数去除每个标签后的空格,最后过滤掉空标签后,返回处理后的标签数组。

2026-01-05 · 1 min · Eagle

解析Protobuf文件并转为JSON格式

解析 Protobuf 文件并转为 JSON 格式 我们知道 Protobuf 文件可以减少体积,方便存储和传输,但在获取文件后,我们还需要将其转换为 JSON 格式,以适配应用进行处理数据。 下面的代码是在微信小程序中使用,将 pb 文件转换为 JSON,然后再使用。 // 小程序根目录执行安装(需开启 npm 支持) // npm install protobufjs // 创建 proto 文件 /proto/item.proto /* syntax = "proto3"; message DataItem { string id = 1; string name = 2; string kw = 3; bool lock = 4; string category = 5; string label = 6; int32 grade = 7; } message DataArray { repeated DataItem items = 1; } */ // 在 app.js 中引入 const protobuf = require('protobufjs'); // 页面 JS 文件 Page({ data: { items: [] }, onLoad() { this.loadProtoData(); }, async loadProtoData() { try { // 1. 下载二进制文件 const { tempFilePath } = await this.downloadFile(); // 2. 读取文件内容 const arrayBuffer = await this.readFile(tempFilePath); // 3. 加载 Proto 定义 const root = await protobuf.load('/proto/item.proto'); const DataArray = root.lookupType('DataArray'); // 4. 解析数据 const decoded = DataArray.decode(new Uint8Array(arrayBuffer)); // 5. 转换格式 const result = decoded.items.map(item => ({ id: item.id || '', name: item.name || '', kw: item.kw || '', lock: typeof item.lock === 'boolean' ? item.lock : false, category: item.category || '', label: item.label || '', grade: item.grade || 1 })); this.setData({ items: result }); } catch (err) { console.error('解析失败:', err); } }, downloadFile() { return new Promise((resolve, reject) => { wx.downloadFile({ url: 'https://your-domain.com/data.bin', success: resolve, fail: reject }); }); }, readFile(tempFilePath) { return new Promise((resolve, reject) => { wx.getFileSystemManager().readFile({ filePath: tempFilePath, encoding: 'binary', success: res => resolve(res.data), fail: reject }); }); } }); 当文件非常大时,解析速度会有点慢啊,为了更进一步的提高速度,我们可以使用 WebAssembly,这里是一个 Wasm 示例: ...

2026-01-05 · 4 min · Eagle