ini 文件操作指南

  今天总结一篇工具箱文章。

  ini 类型文件通常作为程序的初始化文件。不同于我们常见的配置文件通篇 key-value 的键值对形式,ini 文件在键值对的基础之上还有分类节点,比如我们常见的 Mysql 数据库的初始化配置文件 my.cnf或my.ini,其内容格式通常是如下这样的:

[client]
port = 3306
socket = /data/3306/mysql.sock

[mysqld]
user = mysql
port = 3306
socket = /data/3306/mysql.sock
basedir = /usr/local/mysql
datadir = /data/3306/data

  对于这种格式的文件的读取操作,Java中常用 Properties 类是不太好使的。当然,你也可以自己凭着高超的撸码水平去手写工具方法进行读写操作,但肯定还是比较费神的。实际上我们有第三方工具类库可供选择。此处博主分享的类库叫 org.dtools.javaini。整个工具包很轻便,能够支持基本的读写,格式校验等,官方教程很详细,花很少的时间就能上手。当然,结合项目的使用情况,自己还是需要自己进一步封装些方法以便更好的使用。前人种树,后人乘凉,博主也抛转引玉的写了几个:

package module.ini;

import com.alibaba.fastjson.JSONObject;
import org.dtools.ini.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @date: 2019/10/16 19:11
 * @author: chen
 * @desc: org.dtools.javaini-v1.1.00.jar 工具包读写ini 文件工具类
 */
public class IniUtil {

    // ini 文件抽象表示
    private static IniFile iniFile = null;
    // 要操作的文件实例
    private static File file = null;

    // 操作 ini 文件的阅读器和书写器,通过它们来进行具体的读和写操作
    private IniFileReader iniFileReader = null;
    private IniFileWriter iniFileWriter = null;

    /**
     * @param filePath      文件路径
     * @param caseSensitive 是否区分大小写 默认false
     * @param validator     格式校验器
     */
    public IniUtil(String filePath, IniValidator validator, boolean caseSensitive) {
        file = new File(filePath);
        iniFile = new BasicIniFile(validator, caseSensitive);
        try {
            init();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public IniUtil(String filePath) {
        this(filePath, new IniValidator(), false);
    }

    public IniUtil(String filePath, IniValidator validator) {
        this(filePath, validator, false);
    }

    public IniUtil(String filePath, boolean caseSensitive) {
        this(filePath, new IniValidator(), caseSensitive);
    }

    /**
     * 初始化 ini 文件的阅读器和书写器
     */
    private void init() throws IOException {
        iniFileReader = new IniFileReader(iniFile, file);
        iniFileWriter = new IniFileWriter(iniFile, file);
        iniFileReader.read();
    }

    /**
     * 读取 ini 文件转换数据为 Json对象
     */
    public JSONObject getIniFileInfo() {
        Iterator<IniSection> sectionIterator = iniFile.iterator();
        JSONObject jsonObject = new JSONObject();
        while (sectionIterator.hasNext()) {
            IniSection section = sectionIterator.next();
            Iterator<IniItem> itemIterator = section.iterator();
            JSONObject child = new JSONObject();
            while (itemIterator.hasNext()) {
                IniItem item = itemIterator.next();
                child.put(item.getName(), item.getValue());
            }
            jsonObject.put(section.getName(), child);
        }
        return jsonObject;
    }

    /**
     * 获取某个节点下的所有键值对
     */
    public JSONObject getIniBySection(String sectionName) throws Exception {
        IniSection section = getSection(sectionName);
        Iterator<IniItem> iterator = section.iterator();
        JSONObject jsonObject = new JSONObject();
        while (iterator.hasNext()) {
            IniItem item = iterator.next();
            jsonObject.put(item.getName(), item.getValue());
        }
        return jsonObject;
    }


    /**
     * 获取某个节点下某个条目的值
     */
    public Object getItemByName(String sectionName, String itemName) throws Exception {
        JSONObject iniBySection = this.getIniBySection(sectionName);
        return iniBySection.get(itemName);
    }


    /**
     * 新增或修改某节点条目
     */
    public void addOrUpdateItem(String sectionName, String itemName, String itemValue) throws Exception {
        IniSection section = getSection(sectionName);
        IniItem iniItem = section.addItem(itemName);
        if (iniItem == null)
            iniItem = section.getItem(itemName);
        iniItem.setValue(itemValue);
        iniFileWriter.write();
    }


    /**
     * 新增或修改某节点条目 可添加注释
     */
    public void addOrUpdateItem(String sectionName, String itemName, String itemValue,String comment) throws Exception {
        IniSection section = getSection(sectionName);
        IniItem iniItem = section.addItem(itemName);
        if (iniItem == null)
            iniItem = section.getItem(itemName);
        iniItem.setValue(itemValue);
        iniItem.setPreComment(comment);  // 添加前置注释
        iniFileWriter.write();
    }


    /**
     * 新增或修改某节点条目
     */
    public void addOrUpdateItems(String sectionName, Map<String, Object> itemMap) throws Exception {
        IniSection section = iniFile.getSection(sectionName);
        Set<String> items = itemMap.keySet();
        section.addItems(items.toArray(new String[0]));
        iniFileWriter.write();
    }

    /**
     * 新增节点
     */
    public void addSection(String sectionName) throws IOException {
        if (iniFile.addSection(sectionName) == null)
            return;
        iniFileWriter.write();
    }


    /**
     * 删除 某节点
     */
    public void removeSection(String sectionName) throws IOException {
        if (iniFile.removeSection(sectionName) == null)
            return;
        iniFileWriter.write();
    }

    /**
     * 删除 某条目
     */
    public void removeItem(String sectionName, String itemName) throws Exception {
        IniSection section = getSection(sectionName);
        section.removeItem(itemName);
        iniFileWriter.write();
    }


    private IniSection getSection(String sectionName) throws Exception {
        if (!iniFile.hasSection(sectionName)) {
            throw new Exception("The ini file【" + file.getName() + "】 has no section named " + sectionName);
        }
        return iniFile.getSection(sectionName);
    }

}

  作为一个比较简单的工具包,应对 ini 类型文件基本的增删改查足够了。如果你要深度使用,还有些问题需要你自己来解决——

① 工具包中对文件默认采用 ASCII 编码,所以对ASCII 码之外的字符比如中文字符就无法支持,如果读写过程中出现中文将会乱码;     ② 对注释的支持也不足够。常见的注释为 #,但是作者却只给了以 ; 和 // 号开头的注释,,如果原文件有 # 类型的注释,读写操作后会被清理掉;

  由于类库中并没有提供设置编码或注释标注的方法,所以,比较好的办法就是自己下载源码,在源码上进行改动,然后自己打包到自己的项目中使用。以下是博主对代码的改动经验——

    首先,对于字符的问题,作者是在 IniFIleWriter 类中定义了一个表示字符的常量,去掉 final 修饰符,便于使用过程中动态修改编码:

   其次,对于注释,作者在 Commentable 接口中定义了表示注释开头的 ‘;’ 标识,由于是声明在接口中,默认就是static final 的,所以要改成动态设置的比较难办,改动会比较多,比较好的实践也是最简单粗暴的方式——直接改成通常的 # 注释符就可以了:

  最后,重新打成 jar 放入你的项目中或放入你的 maven 仓库。好了,工具方法,就长话短说了,祝使用愉快。

作者:陈本布衣

出处:http://www.cnblogs.com/chenbenbuyi

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏挨踢小子部落阁

内部类, 静态内部类, 局部类, 匿名内部类的解析和区别

众所周知,外部顶级类的类名需和类文件名相同,只能使用public和default。而内部类是指在外部类的内部再定义一个类,类名不需要和文件名相同。内部类可以是静...

11110
来自专栏IT那个小笔记

Action访问

发送请求后就会找到相应的Action类,访问执行execute方法(默认),通过method属性可配置访问的方法

5130
来自专栏.Net Core技术分享

【转】配置子目录Web.config使其消除继承,用虚拟目录创建多个网站的方法

原文链接:http://www.wtnzone.com/post/2011/02/20/Set-Web-Config-to-Turn-Inheritance-O...

8530
来自专栏小码农漫漫积累路

python面向对象的继承-组合-02

管理学生与老师小案例(老师类默认有教书的方法,而学生类是不可以有的,所以不能直接让学生类继承老师类)

9330
来自专栏中科院渣渣博肆僧一枚

matplotlib.collections、(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

6620
来自专栏微信公众号【程序员黄小斜】

夯实Java基础系列1:Java面向对象三大特性(基础篇)

本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

9600
来自专栏安卓圈

广播的注册、发送和接收过程

1)静态注册在应用安装时由PackageManagerService来完成注册过程

6910
来自专栏安卓圈

理解WindowManager

1.Window是一个抽象类,具体的实现类为PhoneWindow,它对View进行管理。WindowManager是一个接口类,继承自接口ViewManage...

6930
来自专栏Coding Diary

Java中实现线程的方式

Java中实现多线程的方式的方式中最核心的就是 run()方法,不管何种方式其最终都是通过run()来运行。

6010
来自专栏Coding Diary

JDK容器类List,Set,Queue源码解读

List,Set,Queue都是继承Collection接口的单列集合接口。List常用的实现主要有ArrayList,LinkedList,List中的数据是...

10320

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励