我遇到了一个问题:我有一个csv文件来准备和提取值。这是代码(并且工作正常):
public class Extract {
final int[] ID = new int[]{0, 10};
final int[] NAME = new int[]{15, 45};
public static void main(String args[]) {
FileInputStream fis = new FileInputStream("C:\\cnab.txt");
String line;
while ((line = fis.readLine()) != null) {
System.out.println(getValue(line, ID));
System.out.println(getValue(line, NAME));
}
}
private String getValue(String line, int[] slice) {
return line.substring(slice[0], slice[1]);
}
}
直到那时好,但我想要一些更具可读性,更优雅的东西,例如:
System.out.println(line.getValue(NAME));
但我们都知道String是final(应该是)。有人有什么建议吗?
答案 0 :(得分:3)
一个选项是拥有一个枚举,你当前有一个int数组:
public enum Field {
ID(0, 10),
NAME(15, 45);
private final int start;
private final int end;
private Field(int start, int end) {
this.start = start;
this.end = end;
}
public string extractFrom(String line) {
return line.substring(start, end);
}
}
然后:
System.out.println(Fields.NAME.extractFrom(line));
System.out.println(Fields.ID.extractFrom(line));
这意味着您可以传递字段(例如,有一组必需的字段进行验证),而不仅仅是int[]
,这可能意味着什么 - 您可以添加任何其他自定义方法和信息。 (例如,对于验证,您可以拥有Pattern
字段...)
答案 1 :(得分:0)
你可以创建自己的类,它是String
的包装器(即组合而不是继承):
public MyString {
private final String string;
public MyString(String string) {
this.string = string;
}
public String getId() {
return string.substring(0, 10);
}
// ...
}
我建议使用与MyString
不同的名称,它应该是描述此对象的内容。如果您不需要任何String
方法,这应该没问题。如果你需要一些,你可以简单地委托他们
public MyString {
// ...
public int length() {
return string.length();
}
// ...
}
如果你需要全部,Project Lombok有一个@Delegate
注释可以解决这个问题,我实际上并不确定。
答案 2 :(得分:0)
看起来您正在寻找一些抽象,允许您查询文件中的不同列。为什么不模仿java.sql.ResultSet
? e.g。
public static void main(String args[]) throws IOException {
BufferedReader file = new BufferedReader(new FileReader("./datacol.txt"));
// Build the recordset for the file
RecordSet rec = new RecordSet(file);
// Iterate on the lines or "records" in the file
while (rec.next()) {
try {
System.out.println(rec.getInt(FooField.ID)); // get the right type
System.out.println(rec.getString(FooField.NAME));
}
catch (Exception e) {
System.out.println(e.toString());
}
}
}
RecordSet
类包装文件并允许您获取行。为此,您需要使用RecordSet
将使用的某个对象来描述文件列。以下是@Jon提出的描述符,enum
,但它实现了一个简单的接口RecordField
。此接口的目的是允许RecordSet
使用不同的字段描述符:
public interface RecordField {
String getFieldValue(String line);
}
// Describe a specific file ("Foo") with its columns (or fields)
public enum FooField implements RecordField {
ID(0,10),
NAME(15, 45);
private final int start;
private final int end;
private FooField(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public String getFieldValue(String line) {
if (line.length() < start || line.length() < end) {
throw new RuntimeException("Invalid line length for "+this);
}
return line.substring(start, end);
}
}
现在,RecordSet
类非常简单,并为字段访问提供了类型值 - 此处仅int
和String
- :
public class RecordSet {
private BufferedReader data;
private String line;
public RecordSet(BufferedReader file) {
this.data = file;
}
public boolean next() throws IOException {
line = data.readLine();
return line!=null;
}
public int getInt(RecordField col) {
checkLine();
String val = col.getFieldValue(line);
return Integer.parseInt(val.trim());
}
public String getString(RecordField col) {
checkLine();
String val = col.getFieldValue(line);
return val.trim();
}
private void checkLine() {
if (line == null) {
throw new RuntimeException("No current record");
}
}
}