Vuelva a escribir la clase de propiedades para realizar la lectura y escritura ordenadas de archivos de propiedades, agregar datos y resolver caracteres chinos ilegibles.

prefacio

        El archivo *.properties es un tipo de archivo de configuración admitido por Java, y Java proporciona la clase de propiedades para leer la información en el archivo de propiedades. En el archivo, la información de configuración que se reutilizará en el proyecto se almacena en forma de pares clave-valor "clave=valor", y la información se lee a través de la clase "Propiedades" para lograr "escribir una vez, llamar a varios lugares". ; la configuración necesita ser un archivo modificado, solo modifique un lugar" efecto .

        Este artículo presenta [lectura y escritura de archivos de propiedades], [adición de datos], [realización de lectura y escritura ordenadas] y [resolución de caracteres chinos ilegibles] .


texto

1. Introducción a la clase Propiedades

        Las propiedades tienen una función especial, que se usa especialmente para cargar el archivo de configuración xxx.properties. Las propiedades se heredan de Hashtable y representan un conjunto persistente de propiedades que se pueden almacenar o cargar desde una secuencia. En la lista de propiedades, cada clave y su valor correspondiente es una cadena.

  • Métodos comunes: 
nombre del método significado
Cadena pública getProperty (clave de cadena) Busca una propiedad en esta lista de propiedades con la clave especificada

objeto público setProperty (clave de cadena, valor de cadena)

Agregue propiedades a Propiedades, sobrescriba si hay una, agregue nuevas si no
carga vacía pública (InputStream in) Leer una lista de propiedades (clave y par de elementos) del flujo de entrada
carga vacía pública  (lector lector) Lee una lista de propiedades (par clave y elemento) de un flujo de caracteres de entrada en un formato simple orientado a líneas
tienda vacía pública  (OutputStream out, comentarios de cadena) escribe una lista de propiedades (clave y pares de elementos) de esta tabla de propiedades en el flujo de salida
almacén vacío público  (escritor escritor, comentarios de cadena) Escribe una lista de propiedades (pares de clave y elemento) de esta tabla de propiedades en el carácter de salida


2. Leer y escribir archivos de propiedades

        Dado que las propiedades se heredan de Hashtable, cuando se escriben nuevas propiedades en el archivo .properties, el orden en que se muestran los resultados puede no ser el orden en el que originalmente establecimos las propiedades. Presta atención a este problema, lo resolveremos más adelante.

  • Las propiedades heredan de Hashtable

  • Con la ayuda de IO stream, use la clase de propiedades para manipular archivos .properties
    // .properties文件的相对路径
    private static final String FILE_ADDRESS = "src/main/resources/application.properties";

    @GetMapping("/test")
    public String test()  {
        log.info("test 接口调用:【开始】 --------------------");
        this.writeIntoText(new Properties());
        Properties prop = this.readFromText();
        log.info("jdbc.username = " + properties.getProperty("jdbc.username"));
        log.info("test 接口调用:【结束】 --------------------");
        return "success";
    }

    /**
     * 模拟向 properties 文件写入数据
     */
    private void writeIntoText(Properties properties){
        OutputStream output = null;
        try {
            output = new FileOutputStream(FILE_ADDRESS);
            properties.setProperty("jdbc.driver", "com.mysql.jdbc.Driver");
            properties.setProperty("jdbc.url", "jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8");
            properties.setProperty("jdbc.username", "root");
            properties.setProperty("jdbc.password", "123456");
            properties.store(output, "tjm modify");
        } catch (IOException io) {
            io.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 读取 properties 文件,返回 Properties 对象
     */
    private Properties readFromText(){
        Properties properties = new Properties();
        InputStream input = null;
        try {
            input = new FileInputStream(FILE_ADDRESS);
            properties.load(input);
        } catch (IOException io) {
            io.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return properties;
    }
  • Ejecutar el código anterior crea varios problemas:
  1. El orden no está ordenado, u ordenado por hash, no el orden del conjunto;
  2. Cada vez que escriba, los datos del archivo de propiedades se sobrescribirán y solo se mostrarán los datos más recientes;
  3. Si el valor contiene chino, se distorsionará;

        A continuación, usaremos esto para resolver estos problemas.


3. Resuelva los problemas de anexión, orden y caracteres ilegibles

2.1 Realizar una lectura y escritura ordenadas

        Personaliza una clase PropertiesUtil, que hereda de Properties. PropertiesUtil proporciona un método que devuelve una Lista compuesta por claves según el orden en que se almacenan, getKeyList(), que puede resolver el problema de la escritura ordenada. En cuanto a la lectura, lo mismo es cierto.

  • ¿Cómo garantizar que el método getKeyList() devuelva una colección de claves ordenadas?

        Al consultar el código fuente del método de propiedades, se encuentra que cuando el método Properties.load() carga contenido del archivo .properties, lee en el orden de los archivos y la capa inferior de Properties.setProperty() El método llama al método HashTable.put() de la clase principal para almacenar.

        HashTable en sí no está ordenado, por lo que la solución es dejar que PropertiesUtil mantenga un conjunto privado que pueda almacenar claves de manera ordenada, y luego reescribir el método put() de la clase principal y usar super.put() en el cuerpo del método como habitual El atributo se almacena y la clave se agrega a la colección de claves almacenadas al mismo tiempo.

        Verifique el código fuente nuevamente y encontró que: Las propiedades almacenan el contenido del objeto actual en el flujo de salida especificado y hay dos métodos, save() y store(), pero su lógica subyacente es la misma, todos llamando a Properties. keys( ) para obtener una Enumeración , luego recorrer la Enumeración y escribir la clave y el valor correspondientes en el flujo de salida a su vez. Para asegurarse de que la escritura esté en orden, es necesario asegurarse de que las claves de elementos extraídas de la Enumeración devuelta por el método transversal keys() estén en orden.

        Por lo tanto, la solución final es reescribir el método keys() para garantizar que las claves obtenidas al recorrer la Enumeración estén en orden.

  • El código completo de la clase PropertiesUtil es el siguiente:
import java.io.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

/**
 * @Description: Java Punk
 * @Created: by JavaPunk on 2023/5/10 16:33
 * @Version: 1.0.0
 */
public class PropertiesUtil extends Properties {
    private static final long serialVersionUID = 1L;
    private List<Object> keyList = new ArrayList<Object>();
    /**
     * 默认构造方法
     */
    public PropertiesUtil() {
    }
    /**
     * 从指定路径加载信息到Properties
     * @param path
     */
    public PropertiesUtil(String path) {
        try {
            InputStream is = new FileInputStream(path);
            this.load(is);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("指定文件不存在!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 重写put方法,按照property的存入顺序保存key到keyList,遇到重复的后者将覆盖前者。
     */
    @Override
    public synchronized Object put(Object key, Object value) {
        this.removeKeyIfExists(key);
        keyList.add(key);
        return super.put(key, value);
    }
    /**
     * 重写remove方法,删除属性时清除keyList中对应的key。
     */
    @Override
    public synchronized Object remove(Object key) {
        this.removeKeyIfExists(key);
        return super.remove(key);
    }
    /**
     * keyList中存在指定的key时则将其删除
     */
    private void removeKeyIfExists(Object key) {
        keyList.remove(key);
    }
    /**
     * 获取Properties中key的有序集合
     * @return
     */
    public List<Object> getKeyList() {
        return keyList;
    }
    /**
     * 保存Properties到指定文件,默认使用UTF-8编码
     * @param path 指定文件路径
     */
    public void store(String path) {
        this.store(path, "UTF-8");
    }
    /**
     * 保存Properties到指定文件,并指定对应存放编码
     * @param path 指定路径
     * @param charset 文件编码
     */
    public void store(String path, String charset) {
        if (path != null && !"".equals(path)) {
            try {
                OutputStream os = new FileOutputStream(path);
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, charset));
                this.store(bw, null);
                bw.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            throw new RuntimeException("存储路径不能为空!");
        }
    }
    /**
     * 重写keys方法,返回根据keyList适配的Enumeration,且保持HashTable keys()方法的原有语义,
     * 每次都调用返回一个新的Enumeration对象,且和之前的不产生冲突
     */
    @Override
    public synchronized Enumeration<Object> keys() {
        return new EnumerationAdapter<Object>(keyList);
    }
    /**
     * List到Enumeration的适配器
     */
    private class EnumerationAdapter<T> implements Enumeration<T> {
        private int index = 0;
        private final List<T> list;
        private final boolean isEmpty;
        public EnumerationAdapter(List<T> list) {
            this.list = list;
            this.isEmpty = list.isEmpty();
        }
        public boolean hasMoreElements() {
            // isEmpty的引入是为了更贴近HashTable原有的语义,在HashTable中添加元素前调用其keys()方法获得一个Enumeration的引用,
            // 之后往HashTable中添加数据后,调用之前获取到的Enumeration的hasMoreElements()将返回false,但如果此时重新获取一个
            // Enumeration的引用,则新Enumeration的hasMoreElements()将返回true,而且之后对HashTable数据的增、删、改都是可以在
            // nextElement中获取到的。
            return !isEmpty && index < list.size();
        }
        public T nextElement() {
            if (this.hasMoreElements()) {
                return list.get(index++);
            }
            return null;
        }
    }
}

2.2 Realice el anexo de datos

       En lo anterior [lectura y escritura de archivos de propiedades], el método de escritura se presenta brevemente, porque se agregarán nuevas propiedades () cada vez, por lo que todos los datos de origen se sobrescribirán cada vez. Después de conocer el motivo, naturalmente encontramos una solución: cargue el archivo fuente antes de escribir y luego agréguelo de manera ordenada.

  • Código fuente: primero cargue el flujo de entrada, luego establezca nuevos atributos y finalmente almacene el flujo de salida
    /**
     * 模拟向 properties 文件追加写入数据
     */
    private void addToText(){
        // 将 PropertiesUtil 换成重写前的 Properties 类,最后写入的顺序是hash排序的
        // Properties properties = new Properties();
        PropertiesUtil properties = new PropertiesUtil();
        InputStream input = null;
        OutputStream output = null;
        try {
            // 先用输入流加载.properties文件
            input = new BufferedInputStream(new FileInputStream(FILE_ADDRESS));
            properties.load(new InputStreamReader(input));
            // 输出流(FileOutputStream)对象,必须在Properties类加载(load)完以后创建(new)
            output = new FileOutputStream(FILE_ADDRESS);
            properties.setProperty("jdbc2.username", "PropertiesUtil Orderly test");
            properties.store(output, "tjm modify");
        } catch (IOException io) {
            io.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  • Resultados de la ejecución de PropertiesUtil:

  •  Resultados de ejecución de propiedades:

2.3 Resolver caracteres chinos ilegibles

        La prueba anterior usa chino. Si el parámetro contiene [chino], habrá caracteres ilegibles. La solución: al ingresar y enviar, configure [charsetName = "utf-8"].

  • Visualización de código:
    /**
     * 模拟向 properties 文件追加写入数据
     */
    private void addToText(){
        // 将 PropertiesUtil 换成重写前的 Properties 类,最后写入的顺序是hash排序的
//         Properties properties = new Properties();
        PropertiesUtil properties = new PropertiesUtil();
        InputStream input = null;
        OutputStream output = null;
        try {
            // 先用输入流加载.properties文件
            input = new BufferedInputStream(new FileInputStream(FILE_ADDRESS));
            properties.load(new InputStreamReader(input, "utf-8"));
            // 输出流(FileOutputStream)对象,必须在Properties类加载(load)完以后创建(new)
            output = new FileOutputStream(FILE_ADDRESS);
            properties.setProperty("jdbc3.username", "PropertiesUtil 有序测试");
            properties.store(new OutputStreamWriter(output, "utf-8"), "tjm modify");
        } catch (IOException io) {
            io.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 读取 properties 文件,返回 Properties 对象
     */
    private Properties readFromText(){
        PropertiesUtil properties = new PropertiesUtil();
        InputStream input = null;
        try {
            input = new FileInputStream(FILE_ADDRESS);
            properties.load(new InputStreamReader(input, "utf-8"));
            log.info("举例说明:jdbc3.username = " + properties.getProperty("jdbc3.username"));
        } catch (IOException io) {
            io.printStackTrace();
        } finally {
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return properties;
    }
  • La pantalla de resultados:


4. Introducción a la configuración de propiedades

        PropertiesConfiguration es una clase que Apache nos ayuda a leer los archivos de propiedades en el orden de los archivos, y puede hacer lo que la clase Properties puede hacer. No solo eso, también tiene muchas funciones adicionales convenientes y prácticas.

  • Código de muestra: demostración funcional
    /**
     * 模拟向 properties 文件写入数据
     */
    private void setParam(){
        try {
            PropertiesConfiguration propsConfig =  new PropertiesConfiguration(FILE_ADDRESS);
            propsConfig.setEncoding("utf-8");
            // 修改属性之后自动保存,省去了propsConfig.save()过程
            propsConfig.setAutoSave(true);
            // setProperty:遇到同名key会替换value,没有则新增
            propsConfig.setProperty("set.name", "123456");
            // addProperty:只会新增,即使遇到遇到同名key也不会替换
            propsConfig.addProperty("add.name", "456789");
        }catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 模拟向 properties 文件读取数据
     */
    private void getParam(){
        try {
            PropertiesConfiguration propsConfig =  new PropertiesConfiguration(FILE_ADDRESS);
            propsConfig.setEncoding("utf-8");
            String username = propsConfig.getString("jdbc.username");
            log.info("举例说明:jdbc.username = " + username);
        }catch (Exception ex) {
            ex.printStackTrace();
        }
    }

Supongo que te gusta

Origin blog.csdn.net/weixin_44259720/article/details/130615132
Recomendado
Clasificación