2022年3月

我们收集了一些最受欢迎的简明指南,它们既能满足你充分利用暑假的愿望,又能满足你为下一个学期做规划的需要。

对一些老师来说,夏天到了,一个漫长的(希望也是放松的)假期也到了。所有我认识的老师都是自豪的终身学习者,尽管暑假过后,又有一个新学期会到来。为了帮助你充分利用暑假时间,与此同时也为即将到来的下一个学期做好准备,我们收集了一些最受欢迎的 简明 指南。

如何让你的学校做好准备(在新冠疫情下)

通过 在 Linux 上来完成所有相关工作,Robert Maynord 老师确保了他的学校为远程学习做好了准备,甚至在疫情前他就这么做了。虽然我们还不知道在今年剩下的时间里会发生什么,但是,如果说新冠疫情向世界展示了什么,那就是 数字转型(指把数字技术融入到教育的各个领域)不仅是可能的,而且对教师和学生来说都是有益的。你可能无权在技术层面上改变课堂的运作方式,但你仍然可以做很多小的改变,为学生创造更灵活的学习体验。

为教师准备的终极开源指南

通过本文,你可以学习如何在课堂上 融入开源原则。开源不仅仅和科技相关,它同时也关于知识共享、团队协作以及为了一个共同目标而努力。你可以把你的教室变成一个共享的空间,让学生们互相学习,就像他们向你学习一样。阅读开源,把开源付诸实践,并鼓励学生们积极参与。

8 个为虚拟教室准备的 WordPress 插件

WordPress Web 平台是一个构建网站的强大工具。在教室里,它可以作为教授 Web 技术、创意写作和学术写作的 一个很好的工具。它也可以被用来帮助远程学习,或者是把日常的学校作业数字化。通过掌握 WordPress 的诸多 [附加功能],你可以从中获取到最大的教育收益。

教孩子们写 Python(交互式游戏)

开源工具可以帮助任何人以一种轻松有趣的方式开始学习 Python —— 那就是制作游戏。当然,Python 涉及到很多方面的东西。别担心,我们有一个课程可以带你从安装 Python 开始,通过简单的文本代码和 “ 海龟 turtle ” 绘图游戏开始你的第一步,一直到中级游戏开发。

  1. 首先,安装 Python,阅读我们的 Python 入门文章,熟悉编程的概念。单单是这篇文章里的内容就可以作为两节或三节不同课程的基础哦。
  2. 然后,如果你熟悉 Jupyter 库的话,可以学习 使用 Python 和 Jupyter 来编写一个简单游戏
  3. 接着,你也可以 在这本 Python 电子书里学到游戏开发的知识,里面会教你如何使用 Git、Python 和 PyGame 库。当你学会了这些基础内容,你可以看看 这本书里的 "游戏测试员" 的有趣创作集合

如果 Python 对你或你的学生来说太难了,那么看看 Thine 吧,它是一个简单的基于 HTML 的交互式的讲故事工具。

教孩子们玩树莓派(编程)

我们的指南中有一篇 树莓派入门指南,其中探索了各种帮助孩子们学习编程的资源。树莓派的特点是它足够便宜,只要花 35 美元,你就可以买到一个全功能的 Linux 电脑。然后你就在上面做任何事,不管是基本的 Python 学习还是搭建实际的网络服务器,因此,它有着巨大的教育潜力。你完全可以为每一个学生都配一个树莓派,或者你也可以让班里的学生共享一个树莓派(Linux 是多用户操作系统,只要设置得当,所有的学生都可以同时使用这个树莓派,直到你说服他们的家长购买更多树莓派)。

一起学习

开放课堂的关键之一是要勇敢地和学生一起学习。作为一个老师,你可能习惯了掌握所有的答案,但是数字世界是不断改变和进化的。不要害怕 你的学生们一起学习 Python、Linux、树莓派或者任何其他东西,一起学习新的基础知识、小技巧和解决问题的新方式。开源是一种经过验证的成功方法,所以不要只是教授开源而已,还要让开源在你的课堂上得以运用。


via: https://opensource.com/article/21/6/open-source-guides-teachers

作者:Seth Kenlon 选题:lujun9972 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

现在你可以在 Arch Linux 中体验 Cutefish 桌面了。本文概述了在 Arch Linux 系统中安装 Cutefish 桌面环境的步骤。

Cutefish 桌面

前一阵子,我们点评了 CutefishOS,它带有看起来非常棒的 Cutefish 桌面,得到了我们的读者的积极反应和关注。因此,我们认为这是一个完美的时机,是时候在你最喜欢的 Arch Linux 中体验一下这个桌面了。

在你进入安装部分之前,这里有一些关于 Cutefish 桌面的小知识。

Cutefish 桌面是 CutefishOS 的一部分,这是一个正在开发的新 Linux 发行版。这个基于 Debian 的 Linux 发行版具有令人难以置信的外观、轻量级的 Cutefish 桌面。

Cutefish 桌面其内部是以 Qt Quick、QML、C++ 和 KDE 框架为基础编写的。这个现代的桌面环境使用 KWin 和 SDDM 进行窗口和显示管理。

Cutefish 桌面为你带来了所寻求的一个完全 macOS 风格的、开箱即用的 Linux 桌面。也就是说,你可以获得令人惊叹的图标、壁纸、全局菜单、带有漂亮通知弹出窗口的顶部栏和底部停靠区。

你可在 [这里] 阅读详细的点评。

在 Arch Linux 中安装 Cutefish 桌面

安装基础 Arch 系统

本指南假设在尝试这些步骤之前,你的系统中已经安装好了基本的 Arch Linux。或者,如果你也安装了任何基于 Arch 的 Linux 发行版,你也可以尝试。只是在这些情况下要注意显示管理的问题。

如果你是 Arch 的新手,你可以参考我们的 Arch Linux 安装指南。

安装 Cutefish 桌面

Arch Linux 社区仓库包含了 Cutefish 组,其中有该桌面运行所需的所有组件。它包括核心软件包、原生应用和下面提到的附加工具。

在你的 Arch Linux 系统的终端提示符下,运行下面的命令来安装所有 Cutefish 桌面软件包。

pacman -S cutefish

A base Arch Linux prompt

Install Cutefish in Arch Linux

接下来,我们需要通过下面的命令安装 Xorg 和显示管理器 SDDM。如果你将 Cutefish 桌面安装在安装有其他诸如 GNOME、KDE Plasma 或 Xfce 等桌面环境的 Arch Linux 中,那么请注意,因为你已经安装了一个显示管理器和 Xorg。所以,你可以轻松跳过这一步。

pacman -S xorg sddm

上述命令完成后,通过 systemctl 启用显示管理器。

systemctl enable sddm

这就是裸机安装 Cutefish 桌面的全部内容。完成后,重启系统,登录后你应该看到 Cutefish 桌面如下。

Cutefish Desktop in Arch Linux

基础安装需要额外的定制,因为它不像 Cutefish OS 那样接近。

安装后的配置

尽管 Arch 仓库中的 Cutefish 组包含了它的原生应用,如计算器和文件管理器,但该桌面缺乏基本的应用,你需要单独安装这些应用来使它成为一个功能齐全的高效桌面。

我建议使用下面的命令来安装以下基本的应用。你可以跳过这一步,或者选择任何其他的应用/组合。

  • Firefox 网页浏览器
  • Kwrite 文本编辑器
  • ttf-freefont 字体
  • VLC 媒体播放器
  • Gwenview 图像查看器
  • GIMP 图像编辑器
  • LibreOffice
  • Transmission
pacman -S firefox ttf-freefont kwrite vlc gwenview gimp libreoffice-still transmission-qt

安装后,打开设置,改变你选择的字体。默认字体是 courier,它在桌面上看起来很糟糕。

按照你的选择完成所有的定制后,重启系统。然后享受 Arch Linux 中的 Cutefish 桌面。

The Stunning Login Lock Screen of Cutefish Desktop

结束语

这个桌面正在开发中,所以在写这篇文章时,你会发现设置项目不多。例如,没有办法改变分辨率、隐藏停靠区等等。不过,你仍然可以安装额外的应用来使用。如果你想做体验一番,可以去试试。

加油。


via: https://www.debugpoint.com/2022/02/cutefish-arch-linux-install/

作者:Arindam 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Linux 内核 5.17 已经发布,它具有更好的硬件支持和核心模块改进。下面是对新功能的简要介绍,并附有下载和安装细节。

Linux 内核 5.17 带来了更多的硬件兼容性

Linux Torvalds 宣发了 Linux 内核 5.17,这是 2022 年第二个稳定版主线内核。这个版本的内核模块中引入了对新处理器、显卡、存储和其他硬件组件的支持。

比内核 5.16 发布后的时间表稍有延迟,Linux 主线内核 5.17 现在可供下载了。这些更新包括对 AMD Zen 系列设备的温度支持;长期存在的软盘挂起错误,几个 ARM/SoC 支持以及各个子系统的性能改进。

我们已经在第一个候选版本发布时介绍了大部分变化,下面是对 Linux 内核 5.17 新特性的快速回顾。

Linux 内核 5.17 的新内容

处理器

Linux 内核中的 ARM64 架构现在包括了 内核并发净化器 Kernel Concurrency Sanitizer (KCSAN)。KSCAN 是一个竞争条件检测器,已经支持了其他架构。而现在 ARM64 也在支持名单上了。另外, 可扩展矩阵扩展 Scalable Matrix Extensions (SME)的初始工作有望为矩阵操作提供更好、更快的支持。

AMD 带来了 基于 k10temp 的 CPU 温度监控,用于 AMD Zen 系列第 19 代 CPU 型号。

一组广泛的 Arm/SoC 支持 进入了 Linux 内核 5.17 中。其中主要包括新的 Snapdragon 8 Gen 1 和 X65 平台。其他 SoC 包括恩智浦 i.MX8ULP、德州仪器 J721S2 和瑞萨 R-Car S4-8。

CPU 的重大变化之一是加入了 AMD 的 P-state 驱动,这是与 Valve 为 Steam Deck 合作开发的。这将提供更好的电源效率,因为透过 ACPI 协作处理器性能控制 Collaborative Processor Performance Controls (CPPC)支持,可以更加细化的控制电源。

这个内核中另一个重要的 RISC-V 变化是支持 sv48,提供了 48 位虚拟地址空间。这使得内核可以对高达 128TB 的虚拟地址空间进行寻址。

这个版本带来了很多笔记本电脑、平板电脑的驱动更新。这里 有一个列表,主要内容是:

  • 为华硕 ROG 笔记本电脑增加了自定义风扇曲线支持。
  • 增加了对 通用手写笔计划 Universal Stylus Initiative (USI)和 NVIDIA Tegra 平板电脑的支持。
  • 对基于 AMD 的笔记本电脑的一些性能改进和修复,涉及到睡眠和声音驱动。

显卡

英特尔的 Alder Lake P 显卡经过前一年的多次迭代,现在已经在主线内核上稳定了。这个内核引入了 对 Raptor Lake S 显卡的首批支持补丁

英特尔的 Gen Icelake 显卡家族 获得了 可变刷新率/自适应同步支持。

一些较新的笔记本电脑带来了内置的隐私屏幕,预计更多的 OEM 厂商会效仿。另外,值得注意的是,GNOME 桌面和其他公司正计划在之后使用这一隐私功能。所以,为了这个以隐私为中心的功能,最初的架构和代码工作都已经包含在这个内核版本中了。

你可以在 这里 找到一个很好的显卡驱动更新列表。

存储

在内核的每个版本中都会对所有主要的文件系统和存储技术进行增量更新。这个版本也会有一些:

  • 主要的更新包括流行的 EXT4 文件系统使用新的 Linux 挂载 API。
  • 像往常一样,F2FSBtrfsXFS 的性能得到改善。
  • FS-Cache 和 CacheFiles 模块 做了 重大重写。

杂项硬件更新

今天谁还在使用软盘?我相信仍然有一些特定的商业用例仍在使用软盘。所以,这就给我们带来了这个特定的补丁,在这个内核版本中。内核中存在一个长期的错误:当系统试图读取一个坏掉的软盘时可能会挂起。所以,这个老毛病终于在这个版本中得到了解决,我希望能让少数仍然使用这种古老存储介质的人为此驻足一下。

其他值得注意的杂项硬件更新包括:

  • 任天堂 GameCube/Wii/Wii U 实时时钟 驱动
  • 一个通用的 USB GNSS( 全球导航卫星系统 Global Navigation Satellite System )驱动程序。
  • Cirrus CS35L41 高清音频编解码器 驱动
  • 许多英特尔 Wi-Fi 驱动程序 改进
  • 英特尔 Alder Lake N 音频 支持。

如何下载和安装 Linux 内核 5.17

我们总是建议不要在你的稳定系统中安装最新的主线内核,除非你拥有特定的新硬件或想做实验。对于普通用户来说,最好是通过你的 Linux 发行版(如 Ubuntu、Fedora)的官方部署渠道等待内核的更新。

如果你仍然想安装,请按照下面的说明来安装 Linux 内核 5.17。

访问 主线内核页面

有两种类型的构建可供选择:通用的和低延迟的。对于标准的系统,你可以下载通用的构建,大部分时间都可以工作。对于音频录制和其他需要低延迟的设置,请下载低延迟的。

通过终端下载以下四个通用软件包并安装:

wget -c https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17/amd64/linux-headers-5.17.0-051700-generic_5.17.0-051700.202203202130_amd64.deb
wget -c https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17/amd64/linux-headers-5.17.0-051700_5.17.0-051700.202203202130_all.deb
wget -c https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17/amd64/linux-image-unsigned-5.17.0-051700-generic_5.17.0-051700.202203202130_amd64.deb
wget -c https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.17/amd64/linux-modules-5.17.0-051700-generic_5.17.0-051700.202203202130_amd64.deb

安装完毕后,重新启动系统。

低延迟和其他架构(ARM)的安装指令是一样的。替换上述 wget 命令中的软件包名称。你可以在主线内核页面找到它们。

对于 Arch Linux 用户来说,预计 Linux 内核 5.17 发布包将在 2022 年 4 月第一周的 Arch .iso 月度刷新中到达。

随着这个版本的发布,合并窗口将为接下来 Linux 内核 5.18 打开。


via: https://www.debugpoint.com/2022/03/linux-kernel-5-17/

作者:Arindam 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

新的 BitB 攻击形式仿造 OAuth 窃取用户凭证

成千上万的网站使用 OAuth 协议,让访问者使用他们在谷歌、Facebook 或苹果等公司的现有账户登录。“浏览器中的浏览器”(BitB)技术利用了这个方案。BitB 不是真正打开第二个浏览器窗口,以连接到用于登录或付款的网站,而是使用一系列 HTML 和 CSS 技巧,显示一个欺骗窗口。其显示的 URL 可以显示一个有效的地址,也有一个挂锁和 HTTPS 前缀。窗口的布局和行为看起来与真实的东西完全一样,除了不能不能被调整大小,完全最大化或拖到主窗口之外。

老王点评:真是防不胜防,一时不注意还真难以发现。

高通公司正在计划为其芯片增加 AV1 支持

发布于 2018 年的开放视频编解码器 AV1 的普及一直很慢,主流视频供应商在等待更广泛的设备支持,而设备厂商则在等待视频供应商提供更多的 AV1 视频。但现在这种情况已经在逐步改变。据称 高通公司正计划在其即将推出的旗舰产品 Snapdragon 移动处理器中加入对 AV1 的原生支持。预计该芯片最早将在今年年底推出。除了高通之外,三星、联发科、博通也都推出了支持 AV1 解码的芯片组,而像谷歌等流媒体设备厂商也在推动其设备增加 AV1 的支持。

老王点评:AV1 什么都好,就是不普及,希望能看到普及吧。

老式 IPv6 设备会泄露你的隐私

在 IPv6 网络中,每个设备都有一个公开的 IPv6 地址。这些地址应该定期换成新的地址。这样当你再次访问一个网站时,仅从你的 IPv6 地址来看,网站并不清楚你的设备已经回来了,这可以给予你一定程度的隐私。在分配地址时,路由器会发送一个网络前缀给客户,然后客户选择一个主机地址。曾经这个主机地址基于设备的硬件 MAC 地址编码,这被称之为 EUI-64。但早在 2007 年就提出的 IPv6 隐私扩展要求随机化地址的主机部分,也就是禁用 EUI-64。而在 研究中发现,大约不到 1/5 的设备仍然默认使用 EUI-64,这造成了隐私泄露。同时,许多 Linux 发行版并没有默认启用隐私扩展,使用 Linux 的产品很可能在不知不觉中将其用户的隐私置于危险之中。

老王点评:协议设计的很好,奈何现实比较可怜。

在这篇文章中,我们将推荐 5 款可以替代微软 Office 的最佳软件,并从功能、操作难易程度等方面,对它们进行比较。看一看哪款更适合你?

可以说,Office 办公软件是微软开发的最优质的软件之一,受到世界各地用户的青睐,广泛应用于各行各业,当属近几十年来软件市场涌现出来的精品。

不过大家都知道,微软 Office 不仅没有开发适用于 Linux 的版本,而且价格高昂。对于企业用户或者个人用户来说,Office 365 的价格就更贵了,远超普通人能接受的价格水平。

那么,有哪些软件可以替代微软 Office 呢?

这篇文章推荐 5 款可以替代微软 Office 的最佳软件。

LibreOffice

LibreOffice

首先推荐的是 LibreOffice。LibreOffice 是一款自由开源的办公套件,由文档基金会开发维护,支持 Linux、macOS 以及 Windows 系统。

LibreOffice 套件包括表格工具 Calc、文字处理工具 Writer、演示工具 Impress、画图工具 Draw 以及数据库工具 Base。

LibreOffice 办公软件的开发十分很活跃,同时不断提升对微软 Office 的兼容性。如果善加利用,LibreOffice 完全可以取代微软 Office。借助丰富的技术文档和社区资源,用户可以迅速掌握 LibreOffice 的使用方法。

企业用户也可以免费使用 LibreOffice,如果需要用它来完成关键工作,用户也可以购买配置服务和支持服务,相关费用十分低廉。

然而,LibreOffice 不提供像 Outlook 一样的邮箱服务。这可能是它的一个小缺点,不过好在现在的邮箱服务都可以在浏览器上运行。

Google Docs

Google Docs

搜索引擎巨头谷歌为用户免费提供了一套网页版的办公套件 —— Google Docs,其中包括 Docs(文档编辑器)、Sheets(表格程序)、Slides(演示程序)。

用户可以在谷歌云盘中免费创建、打开文档。随时随地,自由存取。Google Docs 界面设计优美,内置工具栏、高级选项、拼写检查、语音输入功能(仅支持 Chrome 浏览器)、加密功能以及云存储服务。谷歌也为 iOS 系统和安卓系统提供了移动端,用户可以在移动设备上轻松打开、编辑文档。

Google Docs 最为人称道的功能在于它的模板。有了这些内置模板,用户可以迅速编辑出一份专业的文档。此外,通过邀请其他谷歌用户,还可以使用多人协作在线编辑功能。

如果你需要更多的功能,可以付费使用 Google Workspace。这是一套全面的整合方案,你可以通过 Google Forms 收集信息,并集成到你的文档和表格中、网站编辑工具 Google Sites、Google 日历等服务,保存为文档。

OnlyOffice

OnlyOffice

OnlyOffice(显示名字为 ONLYOFFICE)是一套自由开源的办公软件,包括文本编辑器、表格工具、演示软件,提供共享文件实时协作编辑、修改痕迹记录查看以及制作可供填写的表格等高级功能。

外观上,OnlyOffice 的功能区模仿了微软 Office 365 功能区的设计风格,能让用户快速上手。此外,OnlyOffice 对微软 Office 文件格式(.docx .xlsx 以及 .pptx)的兼容性更好,方便用户与他人共享文件。

值得一提的是,OnlyOffice 还推出了需要付费使用的企业版本 —— ONLYOFFICE Workspace。该版本增加了一些其他的高级功能,提供即时支持服务,非常适合那些预算紧张但对格式兼容性要求又很高的用户。

ONLYOFFICE Workspace 集成了邮箱客户端、客户关系管理产品、项目管理工具以及日历。总体来说,ONLYOFFICE Workspace 是一款不错的软件,但也有一些不足,如拼写检查、打印预览、页面尺寸以及漏洞等问题。不过也不需要过分担心,你可以在 GitHub 上传错误报告,向开发团队寻求帮助。

Softmaker FreeOffice

FreeOffice

FreeOffice 由 SoftMaker 开发,是一套十分优秀的办公软件,包括 TextMaker(可替代 Word)、PlanMaker(可替代 Excel)以及 Presentations(可替代 PowerPoint)。FreeOffice 提供了两种用户界面:带有功能区选项的现代化界面与带有菜单和工具栏的传统界面,两种界面都十分受欢迎。此外,FreeOffice 还为触控设备提供专有的用户界面与功能。

FreeOffice 对 微软 Office 文档格式的兼容性是很好的,可以完成大部分工作。然而,你在处理开放文档格式(ODT)文件时可能会遇到一点麻烦,因为它的支持有限。

FreeOffice 是一款闭源软件。

WPS Office

WPS Office

还记得金山办公软件吗? 它现在的名字叫做 WPS Office。WPS 取 Word, Presentation 与 Spreadsheets 的首字母组合而成。到今天,WPS Office 已有 30 年的发展历史,是老牌办公软件之一。WPS 作为办公软件,功能齐全,支持移动端在内的各类平台。

WPS 最具特色的功能在于支持实时协作编辑。使用 WPS,团队成员可以同时编辑一份共享文档。WPS 还为用户提供了超过 10 万种文档模板,帮助用户编辑出专业美观的文档与演示文件。

WPS 的标准版本可以免费下载使用,不过有一些高级功能需要付费。

如果你需要额外的功能,比如编辑 PDF 文件、云空间扩容、团队协作以及企业支持,可以考虑付费开通会员,使用 WPS 企业版。

注意,这是一款闭源软件,而且可能会推送广告。(LCTT 译注:该公司内部人士表示,免费的 Linux 版没广告。)该软件由中国金山软件公司开发。

对比表

下表基于功能以及其他细节,对上述 5 款办公软进行对比总结。

产品价格是否开源优势劣势
LibreOffice免费开源免费;跨平台;支持多种语言;完全支持 ODF 文件格式;对 微软 Office 兼容性最好;开发活跃不提供邮箱应用;不提供项目管理功能;数据库基于 Java
Google Docs免费闭源免费;跨平台;良好的文档支持;随时随地存取云文档;完美支持移动端需要网络连接;网络连接导致卡顿或延迟;不提供可供安装的版本
OnlyOffice免费(基础功能)开源用户界面酷似微软 Office;对微软 Office 文件拥有更好的兼容性;云集成;支持插件;跨平台基本功能可能出现问题;云集成服务违反欧盟通用数据保护条例;网页端延迟
FreeOffice免费(基础功能)闭源免费;相较于 LibreOffice 更加轻量;支持触屏;良好的微软 Office 兼容性;跨平台免费版本只包括文档、表格与演示功能;其他产品需要付费;对 ODT 文件格式的支持有限;闭源软件
WPS Office免费闭源良好的微软 Office 兼容性;跨平台;标签界面;支持多语言闭源软件;可能弹出广告

我们推荐

抛开所有这些优势和劣势不管,如果你还不确定哪一款才是最适合你的,我推荐你使用 LibreOffice。因为 LibreOffice 与 TDF 格式前景广阔,开发活跃,在全世界都拥有广泛的支持。LibreOffice 有着庞大的在线知识库,为用户提供丰富的使用技巧。通过在 LibreOffice 中使用 Basic 语言或者 Python 宏,你还可以轻松实现办公自动化。

总结

我希望,我们的推荐能帮助你选择适合自己的可替代微软 Office 的办公软件。 说实话,上述软件没有一个能真正比得上微软 Office。但是并不是每个人都能付得起微软 Office 高昂的费用,我相信以上 5 款软件对这部分人来说会是不错的选择。

一些图片来源:上述软件所属公司


via: https://www.debugpoint.com/2022/03/best-alternatives-microsoft-office-2022/

作者:Arindam 选题:lujun9972 译者:aREversez 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在你使用 Java 编写软件时实现持久化配置。

 title=

当你编写一个应用时,你通常都会希望用户能够定制化他们和应用交互的方式,以及应用与系统进行交互的方式。这种方式通常被称为 “ 偏好 preference ” 或者 “ 设置 setting ”,它们被保存在一个 “偏好文件” 或者 “配置文件” 中,有时也直接简称为 “ 配置 config ”。配置文件可以有很多种格式,包括 INI、JSON、YAML 和 XML。每一种编程语言解析这些格式的方式都不同。本文主要讨论,当你在使用 Java 编程语言 来编写软件时,实现持久化配置的方式。

选择一个格式

编写配置文件是一件相当复杂的事情。我曾经试过把配置项使用逗号分隔保存在一个文本文件里,也试过把配置项保存在非常详细的 YAML 和 XML 中。对于配置文件来说,最重要是要有一致性和规律性,它们使你可以简单快速地编写代码,从配置文件中解析出数据;同时,当用户决定要做出修改时,很方便地保存和更新配置。

目前有 几种流行的配置文件格式。对于大多数常见的配置文件格式,Java 都有对应的 library 。在本文中,我将使用 XML 格式。对于一些项目,你可能会选择使用 XML,因为它的一个突出特点是能够为包含的数据提供大量相关的元数据,而在另外一些项目中,你可能会因为 XML 的冗长而不选择它。在 Java 中使用 XML 是非常容易的,因为它默认包含了许多健壮的 XML 库。

XML 基础

讨论 XML 可是一个大话题。我有一本关于 XML 的书,它有超过 700 页的内容。幸运的是,使用 XML 并不需要非常了解它的诸多特性。就像 HTML 一样,XML 是一个带有开始和结束标记的分层标记语言,每一个标记(标签)内可以包含零个或更多数据。下面是一个 XML 的简单示例片段:

<xml>
  <node>
    <element>Penguin</element>
  </node>
</xml>

在这个 自我描述的 self-descriptive 例子中,XML 解析器使用了以下几个概念:

  • 文档 Document <xml> 标签标志着一个 文档 的开始,</xml> 标签标志着这个文档的结束。
  • 节点 Node <node> 标签代表了一个 节点
  • 元素 Element <element>Penguin</element> 中,从开头的 < 到最后的 > 表示了一个 元素
  • 内容 Content : 在 <element> 元素里,字符串 Penguin 就是 内容

不管你信不信,只要了解了以上几个概念,你就可以开始编写、解析 XML 文件了。

创建一个示例配置文件

要学习如何解析 XML 文件,只需要一个极简的示例文件就够了。假设现在有一个配置文件,里面保存的是关于一个图形界面窗口的属性:

<xml>
  <window>
    <theme>Dark</theme>
    <fullscreen>0</fullscreen>
    <icons>Tango</icons>
</window>
</xml>

创建一个名为 ~/.config/DemoXMLParser 的目录:

$ mkdir ~/.config/DemoXMLParser

在 Linux 中,~/.config 目录是存放配置文件的默认位置,这是在 自由桌面工作组 的规范中定义的。如果你正在使用一个不遵守 自由桌面工作组 Freedesktop 标准的操作系统,你也仍然可以使用这个目录,只不过你需要自己创建这些目录了。

复制 XML 的示例配置文件,粘贴并保存为 ~/.config/DemoXMLParser/myconfig.xml 文件。

使用 Java 解析 XML

如果你是 Java 的初学者,你可以先阅读我写的 面向 Java 入门开发者的 7 个小技巧。一旦你对 Java 比较熟悉了,打开你最喜爱的集成开发工具(IDE),创建一个新工程。我会把我的新工程命名为 myConfigParser

刚开始先不要太关注依赖导入和异常捕获这些,你可以先尝试用 javaxjava.io 包里的标准 Java 扩展来实例化一个解析器。如果你使用了 IDE,它会提示你导入合适的依赖。如果没有,你也可以在文章稍后的部分找到完整的代码,里面就有完整的依赖列表。

Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser");
File configFile = new File(configPath.toString(), "myconfig.xml");

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

DocumentBuilder builder = null;
builder = factory.newDocumentBuilder();

Document doc = null;
doc = builder.parse(configFile);
doc.getDocumentElement().normalize();

这段示例代码使用了 java.nio.Paths 类来找到用户的主目录,然后在拼接上默认配置文件的路径。接着,它用 java.io.File 类来把配置文件定义为一个 File 对象。

紧接着,它使用了 javax.xml.parsers.DocumentBuilderjavax.xml.parsers.DocumentBuilderFactory 这两个类来创建一个内部的文档构造器,这样 Java 程序就可以导入并解析 XML 数据了。

最后,Java 创建一个叫 doc 的文档对象,并且把 configFile 文件加载到这个对象里。通过使用 org.w3c.dom 包,它读取并规范化了 XML 数据。

基本上就是这样啦。理论上来讲,你已经完成了数据解析的工作。可是,如果你不能够访问数据的话,数据解析也没有多少用处嘛。所以,就让我们再来写一些查询,从你的配置中读取重要的属性值吧。

使用 Java 访问 XML 的值

从你已经读取的 XML 文档中获取数据,其实就是要先找到一个特定的节点,然后遍历它包含的所有元素。通常我们会使用多个循环语句来遍历节点中的元素,但是为了保持代码可读性,我会尽可能少地使用循环语句:

NodeList nodes = doc.getElementsByTagName("window");

for (int i = 0; i < nodes.getLength(); i++) {
 Node mynode = nodes.item(i);
 System.out.println("Property = " + mynode.getNodeName());
       
 if (mynode.getNodeType() == Node.ELEMENT_NODE) {
   Element myelement = (Element) mynode;
             
   System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent());
   System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent());
   System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent());
 }
}

这段示例代码使用了 org.w3c.dom.NodeList 类,创建了一个名为 nodesNodeList 对象。这个对象包含了所有名字匹配字符串 window 的子节点,实际上这样的节点只有一个,因为本文的示例配置文件中只配置了一个。

紧接着,它使用了一个 for 循环来遍历 nodes 列表。具体过程是:根据节点出现的顺序逐个取出,然后交给一个 if-then 子句处理。这个 if-then 子句创建了一个名为 myelementElement 对象,其中包含了当前节点下的所有元素。你可以使用例如 getChildNodesgetElementById 方法来查询这些元素,项目中还 记录了 其他查询方法。

在这个示例中,每个元素就是配置的键。而配置的值储存在元素的内容中,你可以使用 .getTextContent 方法来提取出配置的值。

在你的 IDE 中运行代码(或者运行编译后的二进制文件):

$ java ./DemoXMLParser.java
Property = window
Theme = Dark
Fullscreen = 0
Icon set = Tango

下面是完整的代码示例:

package myConfigParser;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class ConfigParser {

        public static void main(String[] args) {
                Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser");
                File configFile = new File(configPath.toString(), "myconfig.xml");
                DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = null;
               
                try {
                        builder = factory.newDocumentBuilder();
                } catch (ParserConfigurationException e) {
                        e.printStackTrace();
                }
       
                Document doc = null;
       
                try {
                        doc = builder.parse(configFile);
                } catch (SAXException e) {
                        e.printStackTrace();
                } catch (IOException e) {
                        e.printStackTrace();
                }
        doc.getDocumentElement().normalize();
       
        NodeList nodes = doc.getElementsByTagName("window");
        for (int i = 0; i < nodes.getLength(); i++) {
           Node mynode = nodes.item(i);
           System.out.println("Property = " + mynode.getNodeName());
           
           if (mynode.getNodeType() == Node.ELEMENT_NODE) {
               Element myelement = (Element) mynode;

               System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent());
               System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent());
               System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent());
           } // close if
        } // close for
    } // close method
} //close class

使用 Java 更新 XML

用户时不时地会改变某个偏好项,这时候 org.w3c.dom 库就可以帮助你更新某个 XML 元素的内容。你只需要选择这个 XML 元素,就像你读取它时那样。不过,此时你不再使用 .getTextContent 方法,而是使用 .setTextContent 方法。

updatePref = myelement.getElementsByTagName("fullscreen").item(0);
updatePref.setTextContent("1");

System.out.println("Updated fullscreen to " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent());  

这么做会改变应用程序内存中的 XML 文档,但是还没有把数据写回到磁盘上。配合使用 javaxw3c 库,你就可以把读取到的 XML 内容写回到配置文件中。

TransformerFactory transformerFactory = TransformerFactory.newInstance();

Transformer xtransform;
xtransform = transformerFactory.newTransformer();

DOMSource mydom = new DOMSource(doc);
StreamResult streamResult = new StreamResult(configFile);

xtransform.transform(mydom, streamResult);

这么做会没有警告地写入转换后的数据,并覆盖掉之前的配置。

下面是完整的代码,包括更新 XML 的操作:

package myConfigParser;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class ConfigParser {

        public static void main(String[] args) {
                Path configPath = Paths.get(System.getProperty("user.home"), ".config", "DemoXMLParser");
                File configFile = new File(configPath.toString(), "myconfig.xml");
                DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = null;
               
                try {
                        builder = factory.newDocumentBuilder();
                } catch (ParserConfigurationException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
       
                Document doc = null;
       
                try {
                        doc = builder.parse(configFile);
                } catch (SAXException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                }
        doc.getDocumentElement().normalize();
        Node updatePref = null;
//        NodeList nodes = doc.getChildNodes();
        NodeList nodes = doc.getElementsByTagName("window");
        for (int i = 0; i < nodes.getLength(); i++) {
           Node mynode = nodes.item(i);
           System.out.println("Property = " + mynode.getNodeName());
           
           if (mynode.getNodeType() == Node.ELEMENT_NODE) {
               Element myelement = (Element) mynode;

               System.out.println("Theme = " + myelement.getElementsByTagName("theme").item(0).getTextContent());
               System.out.println("Fullscreen = " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent());
               System.out.println("Icon set = " + myelement.getElementsByTagName("icons").item(0).getTextContent());

               updatePref = myelement.getElementsByTagName("fullscreen").item(0);
               updatePref.setTextContent("2");
               System.out.println("Updated fullscreen to " + myelement.getElementsByTagName("fullscreen").item(0).getTextContent());          
           } // close if
           
        }// close for

        // write DOM back to the file
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer xtransform;

        DOMSource mydom = new DOMSource(doc);
        StreamResult streamResult = new StreamResult(configFile);

        try {
                xtransform = transformerFactory.newTransformer();
                xtransform.transform(mydom, streamResult);
        } catch (TransformerException e) {
                e.printStackTrace();
        }
                       
    } // close method
} //close class

如何保证配置不出问题

编写配置文件看上去是一个还挺简单的任务。一开始,你可能会用一个简单的文本格式,因为你的应用程序只要寥寥几个配置项而已。但是,随着你引入了更多的配置项,读取或者写入错误的数据可能会给你的应用程序带来意料之外的错误。一种帮助你保持配置过程安全、不出错的方法,就是使用类似 XML 的规范格式,然后依靠你用的编程语言的内置功能来处理这些复杂的事情。

这也正是我喜欢使用 Java 和 XML 的原因。每当我试图读取错误的配置值时,Java 就会提醒我。通常,这是由于我在代码中试图获取的节点,并不存在于我期望的 XML 路径中。XML 这种高度结构化的格式帮助了代码保持可靠性,这对用户和开发者来说都是有好处的。


via: https://opensource.com/article/21/7/parsing-config-files-java

作者:Seth Kenlon 选题:lujun9972 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出