我有这段数据(这只是整个文件一行的一部分):
000000055555444444******4444 YY
我实现了这个CSV配置文件,以便能够读取数据的每个部分并解析它:
128-12,140-22,YY
第一对(128-12)表示开始阅读的行中的哪个位置,然后表示要读取的字符数量,第一对用于帐号。
第二对,如果是卡号。
thir参数用于注册表名称。
无论如何,我所做的是String.split(“,”),然后将数组[0]指定为帐号,依此类推。
但我想将CSV配置文件更改为Property文件,但我不确定如何实现该解决方案,如果我使用Properties文件,我必须按顺序添加一堆if / then为了正确地映射我的价值观,这就是我正在考虑的事情:
Property cfg = new Property();
cfg.put("fieldName", "accountNumber");
cfg.put("startPosition", "128");
cfg.put("length", "12");
但是我必须说if(“fieldName”.equals(“accountNumber”))然后分配accountNumber;有没有办法以这样的方式实现这一点,我可以避免实施所有这些决定?现在用我的解决方案我不必使用ifs,我只说accountNumber = array [0];就是这样,但我不认为这是一个很好的解决方案,我认为使用Property会更优雅或更有效
编辑:
这可能需要更多澄清,我正在展示的这些数据是我正在为客户端做的解析程序的一部分;数据为许多客户提供信息,我必须解析从他们那里收到的大量数据,为了将其转换为PDF文件而更具可读性,到目前为止该程序正在生产中,但我我试图稍微重构一下。所有客户的信息都保存在不同的Registry类中,每个类都有自己的一组具有唯一信息的字段,让我们说这就是RegistryYY的样子:
class RegistryYY extends Registry{
String name;
String lastName;
PhysicalAddress address;
public RegistryYY(String dataFromFile) {
}
}
我想实现Property解决方案,因为通过这种方式,我可以使用Property来解析文件,或者正确地解释数据以供每个Registry类拥有,我的意思是,Registry应该知道它需要什么数据从文件收到的数据对吗?我认为,如果我这样做,我可以使每个注册表成为观察者,他们将通过检查存储在该文件中的注册表名称来决定从文件读取的当前行是否属于他们。当前行然后他们将初始化的Registry返回给调用对象,该调用对象只关心接收和存储Registry类。
编辑2:
我创建了这个函数来返回存储在每一行位置的值:
public static String getField(String fieldParams, String rawData){
// splits the field
String[] fields = fieldParams.split("-");
int fieldStart = Integer.parseInt(fields[0]); // get initial position of the field
int fieldLen = Integer.parseInt(fields[1]); // get length of field
// gets field value
String fieldValue = FieldParser.getStringValue(rawData, fieldStart, fieldLen);
return fieldValue;
}
哪个适用于CSV文件,我想更改实现以使用Property文件。
答案 0 :(得分:0)
您是否有任何理由需要将记录布局暴露给外界?是否需要配置?
我认为您提议使用Property文件比使用CSV文件的当前方法更好,因为它更具描述性和意义。我只想添加一个"类型"也属于您的属性定义以强制执行转换,即对于Numeric / String / Date / Boolean。
我不会使用" if"用于处理属性文件的语句。您可以在开始时将所有属性加载到Array中,然后针对数据文件的每一行迭代数组,并相应地处理该部分,如下面的伪代码,
for each loop of data-file{
SomeClass myClass = myClassBuilder(data-file-line)
}
myClassBuilder SomeClass (String data-file-line){
Map<column, value> result = new HashMap<>
for each attribute of property-file-list{
switch attribute_type {
Integer:
result.put(fieldname, makeInteger(data-file-line, property_attribute)
Date:
result.put(fieldname, makeDate(data-file-line, property_attribute)
Boolean :
result.put(fieldname, makeBoolean(data-file-line, property_attribute)
String :
result.put(fieldname, makeBoolean(data-file-line, property_attribute)
------- etc
}
}
return new SomeClass(result)
}
}
如果您的记录布局不需要是可配置的,那么您只能在Java应用程序内进行所有转换,甚至不能使用Property文件。
如果您可以使用XML格式获取数据,那么您可以使用JAXB框架并将数据定义放在XML文件中。
答案 1 :(得分:0)
首先,感谢帮助我的人,@ robbie70,@ RC。和@VinceEmigh。
我使用YAML来解析名为&#34; test.yml&#34;的文件。其中包含以下信息:
statement:
- fieldName: accountNumber
startPosition: 128
length: 12
- fieldName: cardNumber
startPosition: 140
length: 22
- fieldName: registryName
startPosition: 162
length: 2
这就是我所做的:
// Start of main
String fileValue = "0222000000002222F 00000000000111110001000000099999444444******4444 YY";
YamlReader reader = new YamlReader(new FileReader("test.yml"));
Object object = reader.read();
System.out.println(object);
Map map = (Map) object;
List list = (List) map.get("statement");
for(int i = 0; i < list.size(); i++) {
Map map2 = (Map) list.get(i);
System.out.println("Value: " + foo(map2, fileValue));
}
}
// End of main
public static String foo(Map map, String source) {
int startPos = Integer.parseInt((String) map.get("startPosition"));
int length = Integer.parseInt((String) map.get("length"));
return getField(startPos, length, source);
}
public static String getField(int start, int length, String source) {
return source.substring(start, start+length);
}
它正确显示输出:
Value: 000000099999
Value: 444444******4444
Value: YY
我知道配置文件可能包含一些列表和其他不必要的值以及可能的内容,也许程序需要一些改进,但我认为我可以从这里开始实现我的想法。 / p>
编辑:
我使用Apache Commons创建了另一个,这是我在配置属性文件中所拥有的:
#properties defining the statement file
#properties for account number
statement.accountNumber.startPosition = 128
statement.accountNumber.length = 12
statement.account.rules = ${statement.accountNumber.startPosition} ${statement.accountNumber.length}
#properties for card number
statement.cardNumber.startPosition = 140
statement.cardNumber.length = 22
statement.card.rules = ${statement.cardNumber.startPosition} ${statement.cardNumber.length}
#properties for registry name
statement.registryName.startPosition = 162
statement.registryName.length = 2
statement.registry.rules = ${statement.registryName.startPosition} ${statement.registryName.length}
这就是我读它的方式:
// Inside Main
String valorLeido = "0713000000007451D 00000000000111110001000000099999444444******4444 YY";
Parameters params = new Parameters();
FileBasedConfigurationBuilder<FileBasedConfiguration> builder =
new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params.properties()
.setFileName("config.properties"));
try {
Configuration config = builder.getConfiguration();
Iterator<String> keys = config.getKeys();
String account = getValue(getRules(config, "statement.account.rules"), valorLeido);
String cardNumber = getValue(getRules(config, "statement.card.rules"), valorLeido);
String registryName = getValue(getRules(config, "statement.registry.rules"), valorLeido);
} catch (org.apache.commons.configuration2.ex.ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// End of Main
public static String getRules(Configuration config, String rules) {
return config.getString(rules);
}
public static String getValue(String rules, String source) {
String[] tokens = rules.split(" ");
int startPos = Integer.parseInt(tokens[0]);
int length = Integer.parseInt(tokens[1]);
return getField(startPos, length, source);
}
我不完全确定,我认为使用YAML文件看起来更简单,但我真的很喜欢Apache Commons Config的控件,因为我可以将Configuration对象传递给每个注册表,并且注册表知道什么&#34;规则&#34;它想要得到,让我们说注册表类只关心&#34; statement.registry.rules&#34;这就是它,YAML选项我还不完全确定如何做到这一点,也许我需要再尝试两种选择,但我喜欢这里的地方去。
PS:
我在fileValue中使用的这个奇怪的值是我正在处理的,现在在行的长度上添加近1,000个字符,你就会理解为什么我想要一个配置文件来解析它(不要问为什么......客户是疯了)