在游戏开发过程中,需要与大量的配置文件打交道,如经验,装备属性,宠物属性等。通常是策划配置好配置文件,然后交个程序处理。这就需要一个通用的配置文件读取工具,将配置文件的内容转为程序可以处理的数据。下面是利用Java反射实现的一个demo版本: 实现原理:反射。 1.FileUtil.java: 这是一个文件工具类,目前只有一个方法,即将读取文件,将文件内容转为String。 注:1.读取后需要与原文件内容保持一致,包括回车换行。 2.注意配置文件的格式:配置文件的每一列都以tab切分;第一行为列的中文注释,第二行为列的属性名,第三行以后才是属性的内容。下面是一个例子: id 名字 年龄 id name age 1000 landon 23 10001 tracy 31 下面看源码,注释很详细:
package
com.cyou.social.tools.config;
import
java.io.BufferedReader;
import
java.io.File;
import
java.io.FileReader;
import
java.io.IOException;
/** */
/** * * 文件工具类 * * @author landon * @version 1.0 2011/8/1 * */
public
class
FileUtils
{ /** */ /** * * 将文件内容转化为文本字符串 * 与文件中的内容保持一致 * * @param fileName 文件名字 * @return */ public static String convertFileToString(String fileName) { StringBuilder builder = new StringBuilder(); File file = new File(fileName); try { BufferedReader reader = new BufferedReader( new FileReader(file)); String str = null ; while ((str = reader.readLine()) != null ) { builder.append(str); builder.append( " \r\n " ); // 保持一致,添加回车换行符 } } catch (IOException e) { e.printStackTrace(); } return builder.toString(); } }
2.ConfigBaseData.java: 这是配置文件基础对象类。主要功能是读取配置文件内容然后加到一个集合中。 注:1.每一个配置文件都对应一个ConfigBaseData的一个子类 2.每一个ConfigBaseData对象的内容即为配置文件的一行,返回的集合是配置文件的所有行,即所有内容。 下面是源码,注释写的很详细:
package
com.cyou.social.tools.config;
import
java.lang.reflect.Field;
import
java.text.SimpleDateFormat;
import
java.util.Date;
import
java.util.List;
/** */
/** * * 配置文件基础对象类,利用反射设置Field的值 * 忽略了一些条件判断和异常捕捉 * * @author landon * @version 1.0 2011/8/1 * */
public
class
ConfigBaseData
implements
Cloneable
{ /** */ /** * 每一个配置文件都会对应有一个ConfigBaseData的子类型 * 配置文件的每一行数据即为一个ConfigBaseData对象 * 利用反射初始化每一个对象的属性为配置文件中的内容列 * 将配置文件的所有数据加到一个List中 * * @param convertString 配置文件内容字符串 * @param configDataClass 具体的配置文件类Class * @param configDataList 读取配置文件后的集合对象 */ public static final void initialAllObjects(String convertString, Class <? extends ConfigBaseData > configDataClass, List < ConfigBaseData > configDataList) { String[] linesArray = convertString.split( " \r\n " ); // 回车换行符切分 String[] tabArray = linesArray[ 1 ].split( " \t " ); // tab划分列的type/属性名/域 // 从第三行开始读取内容 for ( int i = 2 ;i < linesArray.length;i ++ ) { String[] contentTabArray = linesArray[i].split( " \t " ); // 读取内容 ConfigBaseData baseData = null ; try { baseData = configDataClass.newInstance(); // 实例化 } catch (Exception e) { e.printStackTrace(); } if (baseData != null ) { initalOneObject(baseData, tabArray, contentTabArray); } configDataList.add(baseData); // 加入到一个集合类中 } } /** */ /** * * 初始一个配置文件对象的属性值 * * @param data * @param filedType 配置文件的列名 * @param fieldContent 配置文件列名对应的内容 */ public static final void initalOneObject(ConfigBaseData data,String[] filedType,String[] fieldContent) { for ( int i = 0 ;i < filedType.length;i ++ ) { data.setFieldValue(filedType[i], fieldContent[i]); } } /** */ /** * * 利用反射设置域值 * * @param key 配置文件的filed key(属性名) * @param value 配置文件filed对应的value(属性值) * @return */ public boolean setFieldValue(String key,String value) { try { Field filed = getClass().getField(key); // 得到属性所对应的Field对象 Class <?> fieldType = filed.getType(); // 得到属性的类型 if (fieldType == Integer.TYPE) // int类型 { filed.set( this , Integer.parseInt(value)); // this表示运行时的那个对象 } else if (fieldType == Integer. class ) // Intege类型 { filed.set( this , Integer.valueOf(value)); } else if (fieldType == Short.TYPE) // short类型 { filed.set( this , Short.parseShort(value)); } else if (fieldType == Short. class ) // Short类型 { filed.set( this , Short.valueOf(value)); } else if (fieldType == Long.TYPE) // long类型 { filed.set( this , Long.parseLong(value)); } else if (fieldType == Long. class ) // Long类型 { filed.set( this , Long.valueOf(value)); } else if (fieldType == Float.TYPE) // float类型 { filed.set( this , Float.parseFloat(value)); } else if (fieldType == Float. class ) // Float类型 { filed.set( this , Float.valueOf(value)); } else if (fieldType == Double.TYPE) // double类型 { filed.set( this , Double.parseDouble(value)); } else if (fieldType == Double. class ) // Double类型 { filed.set( this , Double.valueOf(value)); } else if (fieldType == Boolean.TYPE) // boolean类型 { filed.set( this , Boolean.getBoolean(value)); } else if (fieldType == Boolean. class ) // Boolean类型 { filed.set( this , Boolean.valueOf(value)); } else if (fieldType == String. class ) // String类型 { filed.set( this , value); } else if (fieldType == Date. class ) // Date类型 { filed.set( this , new SimpleDateFormat( " yyy-MM-dd hh:mm:ss " ).parse(value)); } return true ; } catch (Exception e) { e.printStackTrace(); } return false ; } }
下面我们就可以简单的熟悉一下这个工具的用法: a.首先需要一个配置文件,testConfig.txt,放在工程下面的res目录下,内容和刚开始举得例子一样,注意格式: id 名字 年龄 id name age 1000 landon 23 10001 tracy 31 b.写一个该配置文件对应的配置文件类,TestConfigData.java,注意这个类需要继承ConfigBaseData,并且类中的属性名需要和上面的配置文件中的列名一致。下面是源码,注释很详细:
package
com.cyou.social.tools.config;
/** */
/** * * 配置文件testconfig对应的文件类,需要继承ConfigBaseData * 类的属性名需要和配置文件的列名需要保持一致 * 为方便测试,属性都设置public,如果设置成了private,需要设置field的accessible方法 * * @author landon * */
public
class
TestConfigData
extends
ConfigBaseData
{ /** */ /** id */ public int id; /** */ /** 名字 */ public String name; /** */ /** 年龄 */ public int age; }
c.下面就可以测试了:Client.java:
package
com.cyou.social.tools.config;
import
java.util.ArrayList;
import
java.util.List;
/** */
/** * * 配置文件工具测试类 * * @author landon * */
public
class
Client
{ public static void main(String args) { // 将工程下res目录下的testConig的配置文件转为字符串 String fileString = FileUtils.convertFileToString( " res\\testconfig.txt " ); // 所有的数据集合 List < ConfigBaseData > list = new ArrayList < ConfigBaseData > (); try { ConfigBaseData.initialAllObjects(fileString, TestConfigData. class , list); } catch (Exception e) { e.printStackTrace(); } // 测试查看,遍历输出 for (ConfigBaseData data : list) { TestConfigData testData = (TestConfigData)data; System.out.println(testData.id); System.out.println(testData.name); System.out.println(testData.age); System.out.println(); } } }
哈哈,当然测试通过了。这只是一个demo版本,还需要很多细节去改进,比如一些条件判断和异常捕捉等。