novelWriter 文档文件格式深入解析:以 Mr. Nobody 人物笔记为例剖析存储结构与标记语法

发布时间:2026/10/14 20:32:19

novelWriter 文档文件格式深入解析:以 Mr. Nobody 人物笔记为例剖析存储结构与标记语法 桌面应用【免费下载链接】novelWriternovelWriter is an open source plain text editor designed for writing novels项目地址https://gitcode.com/gh_mirrors/no/novelWriter点击查看免费下载导读本文以 novelWriter 官方示例项目tests/_lipsum中的一个人物笔记文件 tests/_lipsum/content/4c4f28287af27.md 为解剖样本逐层拆解 novelWriter 的文档文件格式从 TOML 元数据头、tag/plot引用行、%Short注释修饰符到 52 位随机句柄、nwProject.nwx项目结构与索引重建机制。读完本文你将能完全读懂任何 novelWriter 项目中的.md文档理解标签与引用在底层如何关联并掌握手动编辑文档后的正确补救流程。一、文件定位这是一个什么样的人物笔记在tests/_lipsum目录下保存着一整套完整的 novelWriter 示例项目项目名Lorem Ipsum作者 lipsum.com见 tests/_lipsum/nwProject.nwx。项目结构中共有 22 个条目分属Novel正文、Characters人物、Plot剧情、World世界、Trash回收站五个根节点。目标文件4c4f28287af27.md在项目 XML 中注册为item handle4c4f28287af27 parent67a8707f2f249 root67a8707f2f249 order0 typeFILE classCHARACTER layoutNOTE meta expandedno headingH1 charCount1864 wordCount284 paraCount3 cursorPos70 / name statussbaa94f importid6b1d0 activeyesMr. Nobody/name /item也就是说这是一个挂在Characters根节点67a8707f2f249下的、类别为CHARACTER、布局为NOTE的人物笔记文件。它对应项目树中名为Mr. Nobody的条目而文档内部标题则是Nobody Owens取自尼尔·盖曼小说《坟场之书》的主人公名用于演示标签引用关系。二、TOML 元数据头文件自描述的身份证文档开头是被包裹的 TOML 格式元数据块共 8 个字段这是 novelWriter 当前版本的文档头格式 name Mr. Nobody parent 67a8707f2f249 handle 4c4f28287af27 class CHARACTER layout NOTE textHash 3bea02c22084574351f3cf43e7af5b6110d996e8 createdDate Unknown updatedDate 2026-08-01 21:51:21 各字段含义与写入逻辑对应如下字段示例值说明nameMr. Nobody文档在项目树中的显示名称对应 XML 中的nameparent67a8707f2f249父级条目句柄这里指向 Characters 根节点handle4c4f28287af27文档自身句柄即文件名主体也是 XML 中item的 handle 属性classCHARACTER条目类别对应 nwItemClass 枚举NOVEL / PLOT / CHARACTER / WORLD / TIMELINE / OBJECT / ENTITY / CUSTOM 等layoutNOTE条目布局只有两种DOCUMENT正文文档与NOTE项目笔记见 nwItemLayout 枚举textHash3bea02c2…正文部分不含元数据头的 SHA-1 哈希用于检测文件是否被外部修改createdDateUnknown创建时间旧文件迁移时可能缺失而显示UnknownupdatedDate2026-08-01 21:51:21最近一次保存时间仅当正文哈希变化时才更新这些字段并非手写而是由 novelwriter/core/document.py 中的ProjectDocument.writeDocument()第 229 行在每次保存时自动生成写入前先计算正文 SHA-1 哈希哈希与上次不同则刷新updatedDate文件不存在则同时写入createdDate元数据头通过NTomlParser(flatTrue)序列化拼装为\n…\n\n前缀再写入.tmp临时文件成功后replace覆盖原文件先写临时文件再替换保证断电时旧数据不丢失读取时由_splitHeader()第 372 行识别开头的行最多读取MAX_META_LINES 20行作为元数据其余内容视为正文。值得注意storage 格式文档 docs/source/technical/storage.rst 提到文档扩展名为.nwd但当前源码如quickReadText()中的content / f{tHandle}.md与tests/_lipsum/content/目录下的实际文件均使用.md扩展名说明 2.x 系列已统一为.md。三、正文标记语法标题、标签、引用与注释去掉元数据头后正文是一段纯文本共由四类语法元素组成3.1 标题行# Nobody Owens#前缀表示一级标题H1。novelWriter 支持的标题层级由 novelwriter/text/formats.py 的processHeading()第 70 行解析前缀层级说明#H1章节标题Part 级##H2章标题Chapter 级###H3场景标题Scene 级####H4小节标题Section 级#!/##!/###!H1/H2/H3带标记隐藏标题用于小说封面页、献词、序言等不进入正文统计的文档示例项目中即大量使用了#!与##!变体例如 tests/_lipsum/content/7a992350f3eb6.md 的#! Lorem Ipsum和 tests/_lipsum/content/88d59a277361b.md 的##! Prologue。每个文档只允许一个一级标题索引据此划分各标题下的字数统计区间。3.2 标签行tag: Bod | Nobody Owenstag是 novelWriter 的关键字行语法用于定义标签Tag并建立跨文档引用。本文件中该行声明了两个标签Bod与Nobody Owens同一行可用|分隔多个值。关键字行在 novelwriter/constants.py 的nwKeyWords类第 190 行中统一定义完整的 12 个关键字为关键字作用关联类别tag定义标签仅此关键字有定义能力—pov视角人物引用CHARACTERfocus焦点人物引用CHARACTERchar出场人物引用CHARACTERplot剧情线引用PLOTtime时间线引用TIMELINElocation地点引用WORLDobject物件引用OBJECTentity实体引用ENTITYcustom自定义引用CUSTOMstory故事线引用NOVELmention提及引用不建立反向索引—标签与引用的工作方式是在笔记里用tag定义标签在正文文档里用pov/plot/location等引用它。以本项目为例人物笔记定义了Bod标签而场景文件 tests/_lipsum/content/88243afbe5ed8.md 中写着### Scene One pov: Bod plot: Main location: Europe %Synopsis: …这样编辑器就能把场景中的视角人物Bod反查回Mr. Nobody笔记并在引用面板中展示双向关联。关键字行要求写在标题之后、正文之前pov: Bod这种引用写法要求被引用的标签已经存在于某个笔记的tag行中否则会提示未定义标签。3.3 注释修饰符行%Short: The Hero以%开头的行是注释行novelWriter 的注释体系比普通 Markdown 更丰富。processComment()novelwriter/text/formats.py 第 52 行支持如下修饰符语法类型用途%Short: 文本SHORT文档摘要如本文件的The Hero可显示在项目树/大纲中%Synopsis: 文本SYNOPSIS场景/章节情节摘要显示在编辑区底部预览%Note.Key: 文本NOTE带键的笔记注释如%Note.Purpose: Introduction%Footnote.f9kgf: 文本FOOTNOTE配合正文[footnote:f9kgf]标记的脚注定义%Story: 文本STORY剧情线说明% 普通注释PLAIN无修饰符的普通注释如示例中的% Exctracted from the lipsum.com website.%~ 忽略行IGNORE完全忽略脚注键由索引自动生成genNewNoteKey()novelwriter/core/index.py 第 1032 行用style[:1] 4 位随机字符生成形如f9kgf的 5 字符键。在 tests/_lipsum/content/88d59a277361b.md 中可以同时看到[footnote:f9kgf]行内标记与%Footnote.f9kgf:定义行。3.4 正文段落其余行即普通正文段落本文件中是三段 lipsum.com 生成的拉丁占位文本。除此之外示例项目还展示了其他正文语法[NEW PAGE]分页符tests/_lipsum/content/8c58a65414c23.md、 文本 居中标记与[field:allWords]动态字段tests/_lipsum/content/7a992350f3eb6.md、以 Tab 缩进表示引用块tests/_lipsum/content/846352075de7d.md等。四、句柄与存储布局文档为什么叫4c4f28287af27文件名4c4f28287af27并非随机乱码而是文档的句柄handle。根据 docs/source/technical/storage.rst 的说明句柄是一个52 位随机数以十六进制字符串表示——52 位恰好对应 13 个十六进制字符与本文件名的长度一致。采用这种加密式命名的原因有三规避不同操作系统对文件名的命名限制文件名与文档在项目中的显示名称解耦改名不影响文件路径便于配合版本控制与文件同步工具。一个 novelWriter 项目的物理布局如下项目文件夹/ ├── nwProject.nwx # 主项目文件结构、设置、元数据XML缩进格式化 ├── nwProject.lock # 项目锁文件 ├── ToC.txt # 文档目录表标签与存储位置的对照 ├── content/ # 所有文档正文即 handle.md └── meta/ # 半重要数据 ├── index.json # 项目索引缓存可重建 ├── builds.json # 手稿构建定义 ├── options.json # 各文档 GUI 选项缓存 ├── userdict.json # 拼写检查自定义词表 ├── sessions.jsonl # 写作会话统计JSON Lines └── views.json主项目文件nwProject.nwx中的content节点记录了全部 22 个条目及其父子关系、状态status、重要性import、标题层级与字数统计。当前项目文件格式版本为 1.6历史版本演进记录在 novelwriter/core/projectxml.py 第 54-67 行1.0 为原始格式1.1 引入统一content文件夹替代早期data_X分目录1.3 将布局缩减为 DOCUMENT/NOTE 两种1.5 起改为更紧凑的属性式条目存储并加入id属性本示例项目即为 fileVersion 1.5。五、索引与标签关联底层如何把人物笔记串起来文档被保存时novelWriter 会重新扫描并更新项目索引见 novelwriter/core/index.py 的Index类。索引保存四类核心信息每个文档每个标题层级的位置与字数统计文档与笔记中出现的所有标签所有引用行的关联关系谁引用了谁脚注等注释键。索引的持久化文件是meta/index.json其结构可参考测试基准文件 tests/_reference/coreIndex_LoadSave_tagsIndex.json。该文件属可丢失、可重建级别从Tools菜单即可手动重建整个索引。如果手动编辑了content/下的文档重新打开项目时必须重建索引否则编辑器无法感知外部改动——这正是 storage 文档给出的两条明确警告不应自行向项目文件夹添加文件可以谨慎地编辑content/下的纯文本但编辑nwProject.nwx可能使项目不可读甚至崩溃。索引还负责检测文档被外部修改ProjectDocument.writeDocument()会先比对文件 mtime/size再比对 SHA-1 哈希发现外部改动且未强制写入时会拒绝保存并置hashError标志见 novelwriter/core/document.py 第 250-265 行。六、占位文本与测试这个样例项目从哪来tests/_lipsum项目是自动化测试的固定样本fixture其正文段落取自 novelwriter/assets/text/lipsum.txt。编辑器内置的Insert Placeholder Text工具novelwriter/tools/lipsum.py 的GuiLipsum正是从该文件读取文本对话框允许设置 1100 段默认 5 段并选择是否随机打乱顺序确认后生成段落1\n\n段落2…的文本插入光标处。对应的 GUI 测试 tests/tools/test_lipsum.py 验证了三件事无项目时无法打开该工具设置段落数后可生成包含Lorem ipsum的文本随机模式下生成的文本非空并能通过nwDocInsert.LIPSUM正确插入到当前文档光标位置。这也解释了为什么示例笔记的正文全部是拉丁占位文本——它们本身就是用于测试和演示的数据。七、小结读懂一个 novelWriter 文档的四步法回到开头的4c4f28287af27.md现在可以完整还原它的身份一份CHARACTER 类别、NOTE 布局的人物笔记TOML 头声明了它的名称、父节点、句柄与哈希#标题定义文档内标题tag行定义Bod、Nobody Owens两个标签供正文场景以pov引用plot: Main把人物挂到Main剧情线%Short行提供人物一句话摘要textHash与updatedDate则保证了保存时的变更检测。这套元数据头 标题 标签/引用 注释修饰符 纯文本正文的组合就是 novelWriter 全部项目数据可被版本控制、可被外部工具处理、又能在应用内高效索引的根基。相关文件速查本文解剖样本tests/_lipsum/content/4c4f28287af27.md示例项目主文件tests/_lipsum/nwProject.nwx文档读写实现novelwriter/core/document.py存储格式官方文档docs/source/technical/storage.rst关键字与标签常量novelwriter/constants.py注释/标题语法解析novelwriter/text/formats.py项目索引实现novelwriter/core/index.py占位文本工具novelwriter/tools/lipsum.py 与 tests/tools/test_lipsum.py赞分享桌面应用【免费下载链接】novelWriternovelWriter is an open source plain text editor designed for writing novels项目地址https://gitcode.com/gh_mirrors/no/novelWriter点击查看免费下载相关推荐novelWriter 文档文件格式全解析以《Ancient Europe》世界设定笔记为例novelWriter 文档文件格式全解析以《Ancient Europe》世界设定笔记为例 导读 novelWriter 将每个项目文档以 handle.m桌面应用novelWriter 项目文档文件格式解析以 Alice in Wonderland 世界设定笔记为例novelWriter 项目文档文件格式解析以 Alice in Wonderland 世界设定笔记为例 导读 本文以开源小说写作软件 novelWrite桌面应用novelWriter 文档格式深度解析从 tests/_lipsum 样本看 NWD 文件结构与标记语法novelWriter 文档格式深度解析从 tests/_lipsum 样本看 NWD 文件结构与标记语法 novelWriter 是一个开源、无干扰的纯文本桌面应用上一篇在 Digital Ocean 上手动部署 Prisma 服务从 Droplet 创建到服务上线的完整实战下一篇Power BI 终极图标资源库让数据可视化更简单高效创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/14 20:32:19

artcraft:轻量级浏览器创意工具从架构到性能优化实战

1. 项目缘起与整体设计思路1.1 为什么会有 artcraft 这个想法做创意工具这些年,我越来越强烈地感受到一个矛盾:市面上要么是功能极其强大的专业软件,学习曲线陡峭到让人望而却步;要么是轻量级的小工具,用起来简单但稍微…

2026/10/14 20:27:18

Qwen-Image-2.1本地部署与API发布:GGUF量化+stable-diffusion.cpp实战

1. 为什么要在本地折腾 Qwen-Image-2.1先把结论摆在前面:Qwen-Image-2.1 这个模型,如果你只是偶尔生成几张图玩玩,用在线服务完全够用;但一旦涉及批量出图、私有素材、固定风格微调,或者你想把它接进自己的自动化流程里…

2026/10/14 20:27:18

具身人工智能:物理认知闭环驱动的智能新范式

1. 具身人工智能不是“会走路的AI”,而是重新定义智能边界的物理认知革命具身人工智能这个词最近在科技圈、制造业展会和高校实验室里高频出现,但很多人一听到就下意识联想到人形机器人跳舞、送餐或者做家务——这其实是把结果当成了本质。我带团队做过三…

2026/10/14 23:36:07

Redis从安装到实战:配置、数据结构与缓存问题排查全攻略

先问自己一个问题:有没有遇到过这样的场景——线上接口突然变慢,数据库CPU飙高,用户反馈页面打不开,重启服务后过几分钟又被打爆;或者明明是同一个数据,每次请求都要去数据库查一遍,白白浪费了连…

2026/10/14 23:36:07

告别收藏即掌握:用认知模式重塑知识过程

做知识管理的人,大多经历过一个错觉:把文章存进收藏夹,心里就踏实了;把书里划的线填满页面,就觉得知识已经属于自己;把AI生成的摘要复制进个人笔记,就以为自己完成了学习。这些情况从来不是工具…

2026/10/14 23:36:07

深度学习光流估计实战:从原理到训练调参的完整指南

光流估计是我接触深度学习之后,觉得非常“拧巴”的一个任务。输入是两帧相邻图像,输出的是一个和原图同样大小的二维矢量场,每个像素点告诉你“往哪去了、动了多少”。听起来很直观?等你真的上手调一次模型就会明白,遮…

2026/10/14 23:36:07

前端页面嵌入百度地图:从API接入到白屏排查完整实践

前端页面嵌入百度地图的小demo,这个需求看起来不起眼,但实际做起来,坑比想象中多得多。我最早接触这个需求的时候,以为就是引个脚本、new一个对象、放个容器就完事。结果从申请密钥到地图真正在页面上渲染出来,折腾了小…

2026/10/14 23:36:07

认知模式决定知识管理效率:三种知识处理路径与实操指南

当初我在搭建个人知识库的时候,第一件让我困惑的事情不是工具,而是“为什么信息越来越多,自己却越来越空”。看了很多书,收藏了不少帖子,也做过不少思维导图,可真遇到问题的时候,脑子里的知识点…

2026/10/14 23:31:06

IPO审核两大雷区:应收账款高企与控制权分散的排雷指南

聊一个最近被反复讨论的IPO案例:一家拟上市制造企业,应收账款余额一路飙到11.22亿元,同时公司股权结构高度分散,几个大股东持股比例拉不开差距,谁都没有绝对话语权。这两个问题单独拎出来,都是IPO审核里的高…

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/14 17:41:07

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/14 2:32:55

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/14 0:00:33

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:33

macOS/iOS高精度计时:mach_absolute_time原理与实战

1. 项目概述:为什么mach_absolute_time是 macOS/iOS 时间测量的“黄金标准”在 macOS 和 iOS 开发中,我见过太多人用CFAbsoluteTimeGetCurrent()或NSDate.timeIntervalSinceReferenceDate做性能打点,结果在高精度场景下被系统时钟跳变、NTP 同…

2026/10/14 0:00:33

SCORM课件演示与测试全解析:从API通信到自动化验证

简介:这是一套遵循SCORM标准的交互式课件演示与测试资源,面向E-Learning课程开发者、LMS平台测试人员及在线教学从业者,用于验证课件在不同学习管理系统中的识别、传递与跟踪能力。压缩包共28个文件,约12.07MB,以swf动…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑