在循环之间建立通信,实现对一种config配置文件的元素定位与修改

前言

前不久,笔者在工作中遇到一项任务,内容为实现使用配置文件中元素的注释或者key值来找到该元素,然后对value值进行修改。需要操作的配置文件有3种,properties、config和xml。其中对properties定位和修改元素的功能实现起来非常简单,不值一提。config和xml两种文件操作起来稍微麻烦点,笔者现将实现对config文件按照元素的注释或者key值来定位和修改元素的算法和代码公布。

欢迎各位程序员或者算法爱好者阅读交流,笔者QQ:1072334275,如果问题或者优化意见请QQ联系我。

功能要求

首先,config配置文件的格式如下图:由注释和元素内容组成,注释写在对应元素的上部,元素上下一行分别是左右中括号。当然,注释可能不止一行,元素也可能没有注释。
当前要实现的功能是:无论通过元素的注释或者key值的某段字符串都可以找到该元素,并且得到元素的注释与完整的key、value键值内容,也能修改改元素的value值。
在循环之间建立通信,实现对一种config配置文件的元素定位与修改_第1张图片

编程思想

我们的Java语言在读取文件内容时是按行来逐行读取的,我们可以通过循环来逐行的得到文件的每一行内容。但是在该配置文件中,注释、key值、value值均在不同的相邻行中,因此我们会在不同轮数的循环中得到他们的内容。因此,我们需要在不同轮的循环中建立一种通信机制,让前面的循环告诉后面的循环:你正则得到行是什么内容,需要执行什么动作。这种通信机制,在Java语言中很好实现,我们可以通过变量的自增和对变量值的判断来进行。例如,如果上轮循环中检测到了当前循环读取的行是正确的key值,我们就可以让某个变量进行一次变更,后面的循环读取到这种变更时,就会知道本轮循环要读取的行是value值,需要进行执行存储动作。
下面,我通过具体的算法和代码来为你演示这种编程的思想和方法。

算法

一、元素查找
需要实现的功能是元素可以通过注释或者元素的key值来进行查找,并且找到元素后带出元素的注释、key值、value值等全部内容。具体算法为:
1、使用I/O流逐行读取文件,方法很简单,网上有现成的代码。
2、定义两个变量,i变量作为循环之间进行相互通信的媒介,每次循环通过检查i值判断当前读取到的行是什么内容,需要执行什么动作。getNote变量也是循环间进行相互通信的媒介,当用户输入key值进行查找时,需要判断程序是否先读取到了注释,或者某些元素没有注释直接读取到了元素内容,以便作为后面的循环时是否需要作注释舍弃动作的依据。
3、判断用户输入的是注释还是key值,以用户输入的内容是否包含汉字作为判断依据。
4、根据用户输入的内容类型不同,需要用不同的算法进行计算。
如果用户输入的是注释,则按照以下方法进行:
(1)读取到某一行时先判断其是否为注释,以该行的第一个字符是否为“#”作为依据。如果是注释,将该行先存储起来,再进行判断是否包含用户输入的字符串。
(2)如果在上步中找到当前读取的行包含用户输入的字符串,则说明已经找到我们需要寻找的内容。此时,我们需要将i值的自增一次,来作为已经找到正确注释的标志。
(3)如果当前读取的行不是注释,说明注释内容读取结束,已经开始读取到元素内容,。此时我们需要判断i的值是否自增过,来判断前面读取的注释是否已经找到用户输入的内容。
(4)如果i值自增过一次,说明前面读取的注释是用户需要寻找的元素的注释,此时我们需要通过判断该行的第一个字符是不是“[”来判断此行是不是元素内容的开始。如果如果此行是元素内容的开始,则将i值再次自增,告知后面的循环,即将读取元素key值了。
(5)如果i值出现两次自增,说明本轮循环读取的行为元素的key值,需要进行存储。存储后,i值继续自增,告诉后面的循环,即将读取元素的value值。
(6)如果i值出现了三次自增,说明此行是元素的value值,存储后将结果返回。

如果用户输入的是key值,按照以下算法进行:
(1)读取到某一行时先判断其是否为注释,以该行的第一个字符是否为“#”作为依据。如果是注释,将该行先存储起来。getNote的值进行自增一次,告知后面的循环,前面的循环已经存储了注释内容。
(2)如果此行不是注释,则通过判断当前循环读取的行的第一个字符是否是“[”,来判断此行是不是元素内容的开始。,是的话i值自增一次。
(3)如果此行不是注释,检测i值是否自增过一次,是的话则表示前面读取到元素的开始符号,此次循环读取的行为元素的key值,需要判断本次读取的key值是否包含用户输入的内容,如果包含的话则将i值再次自增即可。不包含的话将i的值还原为0,并且通过检测getNote值是否出现一次或者多次自增来判断是否存储过注释,如果存储过注释的话,存储的注释也需要清空。
(4)如果此行不是注释,检测i值是否自增过两次,如果自增过两次,说明上轮循环中已经将key值校验无误,本轮循环读取到的是正确的value值,需要存储。

二、元素修改
笔者打字打累了,修改算法就省略一下吧,请读者阅读下面的程序代码和代码的注释,来自己体会一下计算过程。我写的程序注释比较详细,相信聪明的读者能够轻易读懂。

程序代码

public class OperateConfig {
	
	//此方法用于在config文件中以注释或者元素的key值查找元素,其中confFilePath表示文件路径,
	//seekContent表示用于查找元素的关键字,可以是元素key值的一部分,也可以是元素注释的一部分
	public static Map<String,String> getConfigElement(String confFilePath,String seekContent) {
	    
	    File confFile = new File(confFilePath);
	   
	    Map<String,String> element=new HashMap();
	    //i变量作为循环之间进行相互通信的媒介,每次循环通过检查i值判断当前读取到的行是什么内容,
	    //是要找的key值,还是要找的value值
	    int i=0;
	    //getNote变量也是循环间进行相互通信的媒介,当用户输入key值进行查找时,需要判断程序是否先读取到
	    //了注释,或者某些元素没有注释直接读取到了元素内容,以便作为后面的循环时是否需要作注释舍弃动作
	    //的依据
	    int getNote=0;
	    String line = "";
	    try {
	    	BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(confFile),"GB2312"));
			while((line=br.readLine()) != null) {
				line=line.trim();
				if(!line.equals("")) {
					//如果用户输入的是注释,我们需要以注释来进行查找。isCNChar()方法在写程序的最下面
					if(isCNChar(seekContent)) {
						//如果当前读取到的行是注释,isNote()方法见程序最下面
						if(isNote(line)) {
							//先把注释存储起来,因为注释不止一行,我们不确定用户输入的是哪一行注释,所以先进性存储
							element.put("note", element.get("note")+line);
							//找到正确的注释,i自增,表示注释找到了
							if(line.contains(seekContent)) {
								//如果找到正确的注释,以i自增作为标志,告诉后面的循环,已经找到正确的注释
								i++;
							}
							continue;
						}else {
							
							//如果在遍历注释时没有找到正确的注释,将已经存储的注释舍弃
							if(i==0) {
								element.put("note","");
							}
							//如果i值出现自增,说明在遍历注释时已经找到正确的注释,此时我们需要在判断当前行
							//不是元素的开始符合,即“[”
							String oneChar=line.substring(0, 1);
							if(i==1) {
								//如果此行是元素的起始符,i再次自增,告诉后面的循环,即将读取key值
								if(oneChar!=null&&oneChar.equals("[")) {
									i++;
									continue;
								}
							}
							if(i==2) {
								//如果i值自增到了2,说明此行是key值,存储后i再次自增,告诉后面的循环即将读取value值
								element.put("key", line);
								i++;
								continue;
							}
							//如果i自增到了3,说明此行是value值
							if(i==3) {
								element.put("value", line);						
								i=0;
								return element;
							}
						}
						
						
					//如果用户输入的不是注释,是key值	
					}else {
						//如果这行是注释,先存储起来
						if(isNote(line)) {
							element.put("note", element.get("note")+line);
							getNote++;;
						}else if(getNote>0){
							String oneChar=line.substring(0, 1);
							//说明元素注释行依据结束,下一行将开始读取元素内容,以i自增1作为标志
							if(oneChar!=null&&oneChar.equals("[")) {
								i++;
								continue;
							}
							//如果i值出现自增,表示本轮循环读取的就是元素的key值,需要判断key值是不是需要找的
							if(i==1) {
								//如果key值正确,将key存储,i再次自增,告诉后面的循环,当前元素正是我们要找的
								if(line.contains(seekContent)) {
									element.put("key", line);
									i++;
									continue;
								}else {
						    //如果key值不正确,则说明当前的元素不是我们要找的,将已经存储的注释舍弃,i值和getNote还原
									i=0;
									getNote=0;
									element.put("note","");
									continue;
								}
							}
							//如果i值已经自增到了2,说明上轮循环key值校验无误,可以存储本轮循环的value值了
							if(i==2) {
								element.put("value", line);
								i=0;
								return element;
							}	
						
						}else {
							String oneChar=line.substring(0, 1);
							if(oneChar!=null&&oneChar.equals("[")) {
								i++;
								continue;
							}
							if(i==1) {
								if(line.contains(seekContent)) {
									element.put("key", line);
									i++;
									continue;
								}else {
									i=0;
									continue;
								}
							}
							if(i==2) {
								element.put("value", line);
								
								i=0;
								return element;
							}

					  }

				  }
					
			  }

		   }
			 
			 
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	    return element;
	}
	
	
	
	//准备方法,实现对config文件按照配置项进行修改,以key值进行查找和修改
	public void updateConfig(String key,String value) {
		// TODO Auto-generated method stub
		File file = new File("E:/config/LBSConfig");
		BufferedReader reader = null;
		List<Map> elementList=new ArrayList();
		StringBuffer sbf = new StringBuffer();
		String line=System.getProperty("line.separator");//平台换行!
		PrintWriter pw=null;
		try {
			reader = new BufferedReader(new InputStreamReader(
					new FileInputStream(file), "GB2312"));
			String tempStr;
			int i=0;
			int y=0;
			Map<String,String> element=new HashMap();
	        while ((tempStr = reader.readLine()) != null) {
	        	//去除空格
	        	tempStr=tempStr.trim();
	        	if(tempStr!=null) {
	        		if(tempStr.equals("")) {
	        			sbf.append(tempStr+line);//保留换行信息
	        		}else {

		        		//截取第一个字符
		        		String oneChar=tempStr.substring(0, 1);
		        		//判断是不是注释
		        		if(oneChar!=null&&oneChar.equals("#")) {
		        			sbf.append(tempStr+line);	
		        		}
		        		//判断是不是元素的开始
		        		if (oneChar!=null&&oneChar.equals("[")) {	
							i++;
							sbf.append(tempStr+line);
							continue;
						}
		        		//判断是不是元素的结尾
		        		if (oneChar!=null&&oneChar.equals("]")){
		        			//创建新对象,用来存储元素
		        			i=0;
		        			sbf.append(tempStr+line);
		        			continue;
						}	
		        		//判断是不是key
		        		if(i==1) {
		        			if(tempStr.equals(key)) {
		        				y++;//通知后面的循环,已经找到需要修改的元素
		        			}
		        			i++;
		        			sbf.append(tempStr+line);
		        			continue;
		        		}
		        		if(i==2) {
		        			
		        			i++;
		        			sbf.append(value+line);//将值换成传入的value存储
		        			y=0;//y重新归于0
		        			continue;
		        		}
	        		}
	        	}
	        }  
	        pw=new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"GB2312")));
            pw.println(sbf);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
		}finally {
			if (reader != null) {
	            try {
	                reader.close();
	            } catch (IOException e1) {
	                e1.printStackTrace();
	            }
	        }
			if(pw!=null) {
                pw.close();
            }
		}
	}
	
	

	
	//准备方法,判断读到的行是不是注释
    public static boolean isNote(String line) {
    	
    	String ch=line.substring(0,1);
    	
    	if(ch.equals("#")) {
    		return true;
    	}else {
    		return false;
    	}
    	
    }
    
    //准备方法,判断读到的行是否包含汉字
    public static boolean isCNChar(String line){
        boolean booleanValue = false;
        for(int i=0; i<line.length(); i++){
            char c = line.charAt(i);
            if(c> 128){
                booleanValue = true;
                break;
            }
        }
        return booleanValue;
    }

}

结束语

算法之所以有趣,是因为算法能将人的智慧赋予给计算机。

你可能感兴趣的:(程序算法,java)