Javaで固定長のフラットファイルを書くのに役立つフレームワーク/ライブラリはありますか?
変換、パディング、配置、フィラーなどを気にせずに、Bean /エンティティのコレクションをフラットファイルに書き込みたい
たとえば、次のようなBeanを解析したいと思います。
public class Entity{
String name = "name"; // length = 10; align left; fill with spaces
Integer id = 123; // length = 5; align left; fill with spaces
Integer serial = 321 // length = 5; align to right; fill with '0'
Date register = new Date();// length = 8; convert to yyyyMMdd
}
...に...
name 123 0032120110505
mikhas 5000 0122120110504
superuser 1 0000120101231
.。
それでもフレームワークを探している場合は、BeanIOをチェックしてください http://www.beanio.org
「レガシー」システムのフォーマットに対応できるフレームワークに遭遇する可能性はほとんどありません。ほとんどの場合、レガシーシステムは標準フォーマットを使用しませんが、フレームワークはそれらを想定しています。レガシーCOBOLシステムとJava/Groovy変換のメンテナーとして、私はこの不一致に頻繁に遭遇します。 「変換、パディング、配置、フィラーなどの心配」は、主にレガシーシステムを扱うときに行うことです。もちろん、その一部を便利なヘルパーにカプセル化することもできます。しかし、ほとんどの場合、Java.util.Formatterに精通する必要があります。
たとえば、デコレータパターンを使用して、変換を行うデコレータを作成できます。以下は少しグルーヴィーです(Javaに簡単に変換できます):
class Entity{
String name = "name"; // length = 10; align left; fill with spaces
Integer id = 123; // length = 5; align left; fill with spaces
Integer serial = 321 // length = 5; align to right; fill with '0'
Date register = new Date();// length = 8; convert to yyyyMMdd
}
class EntityLegacyDecorator {
Entity d
EntityLegacyDecorator(Entity d) { this.d = d }
String asRecord() {
return String.format('%-10s%-5d%05d%tY%<tm%<td',
d.name,d.id,d.serial,d.register)
}
}
def e = new Entity(name: 'name', id: 123, serial: 321, register: new Date('2011/05/06'))
assert new EntityLegacyDecorator(e).asRecord() == 'name 123 0032120110506'
これは、これらの数が多すぎず、オブジェクトが複雑すぎない場合に機能します。しかし、すぐにフォーマット文字列が耐えられなくなります。次に、次のようなDateのデコレータが必要になる場合があります。
class DateYMD {
Date d
DateYMD(d) { this.d = d }
String toString() { return d.format('yyyyMMdd') }
}
したがって、%sでフォーマットできます。
String asRecord() {
return String.format('%-10s%-5d%05d%s',
d.name,d.id,d.serial,new DateYMD(d.register))
}
ただし、かなりの数のBeanプロパティの場合、文字列はまだ粗すぎるため、渡されたCOBOL仕様のように見える列と長さを理解するものが必要なので、次のように記述します。
class RecordBuilder {
final StringBuilder record
RecordBuilder(recordSize) {
record = new StringBuilder(recordSize)
record.setLength(recordSize)
}
def setField(pos,length,String s) {
record.replace(pos - 1, pos + length, s.padRight(length))
}
def setField(pos,length,Date d) {
setField(pos,length, new DateYMD(d).toString())
}
def setField(pos,length, Integer i, boolean padded) {
if (padded)
setField(pos,length, String.format("%0" + length + "d",i))
else
setField(pos,length, String.format("%-" + length + "d",i))
}
String toString() { record.toString() }
}
class EntityLegacyDecorator {
Entity d
EntityLegacyDecorator(Entity d) { this.d = d }
String asRecord() {
RecordBuilder record = new RecordBuilder(28)
record.setField(1,10,d.name)
record.setField(11,5,d.id,false)
record.setField(16,5,d.serial,true)
record.setField(21,8,d.register)
return record.toString()
}
}
レガシーシステムを処理するのに十分なsetField()メソッドを作成したら、それを「フレームワーク」としてGitHubに投稿することを簡単に検討します。これにより、次の貧弱な樹液を再度作成する必要がなくなります。ただし、COBOLが「日付」(MMDDYY、YYMMDD、YYDDD、YYYYDDD)と数値(小数点、明示的な小数点、末尾の区切り文字としての符号、または先頭の浮動小数点文字としての符号)を格納するのを見たすべてのばかげた方法を検討します。次に、なぜ誰もこれに適したフレームワークを作成していないのかを理解し、作成コードの一部をSO例として...;)に投稿することがあります。
niVocity-parsers は、異なるフィールドやパディングなどの行を含む、トリッキーな固定幅フォーマットをサポートするのに大いに役立ちます。
この例をチェックして、架空のクライアントとアカウントの詳細を記述してください。これは、先読み値を使用して、行を書き込むときに使用する形式を識別します。
FixedWidthFields accountFields = new FixedWidthFields();
accountFields.addField("ID", 10); //account ID has length of 10
accountFields.addField("Bank", 8); //bank name has length of 8
accountFields.addField("AccountNumber", 15); //etc
accountFields.addField("Swift", 12);
//Format for clients' records
FixedWidthFields clientFields = new FixedWidthFields();
clientFields.addField("Lookahead", 5); //clients have their lookahead in a separate column
clientFields.addField("ClientID", 15, FieldAlignment.RIGHT, '0'); //let's pad client ID's with leading zeroes.
clientFields.addField("Name", 20);
FixedWidthWriterSettings settings = new FixedWidthWriterSettings();
settings.getFormat().setLineSeparator("\n");
settings.getFormat().setPadding('_');
//If a record starts with C#, it's a client record, so we associate "C#" with the client format.
settings.addFormatForLookahead("C#", clientFields);
//Rows starting with #A should be written using the account format
settings.addFormatForLookahead("A#", accountFields);
StringWriter out = new StringWriter();
//Let's write
FixedWidthWriter writer = new FixedWidthWriter(out, settings);
writer.writeRow(new Object[]{"C#",23234, "Miss Foo"});
writer.writeRow(new Object[]{"A#23234", "HSBC", "123433-000", "HSBCAUS"});
writer.writeRow(new Object[]{"A#234", "HSBC", "222343-130", "HSBCCAD"});
writer.writeRow(new Object[]{"C#",322, "Mr Bar"});
writer.writeRow(new Object[]{"A#1234", "CITI", "213343-130", "CITICAD"});
writer.close();
System.out.println(out.toString());
出力は次のようになります。
C#___000000000023234Miss Foo____________
A#23234___HSBC____123433-000_____HSBCAUS_____
A#234_____HSBC____222343-130_____HSBCCAD_____
C#___000000000000322Mr Bar______________
A#1234____CITI____213343-130_____CITICAD_____
これは大まかな例です。他にも多くの 利用可能なオプション があり、注釈付きJava Beans、見つけることができます ここ のサポートを含みます。
開示:私はこのライブラリの作成者です。オープンソースで無料です(Apache 2.0ライセンス)
ライブラリFixedformat4jは、これを正確に実行するための非常に優れたツールです。 http://fixedformat4j.ancientprogramming.com/
Spring Batch には FlatFileItemWriter
がありますが、Spring Batch API全体を使用しない限り、それは役に立ちません。
しかし、それとは別に、ファイルへの書き込みを簡単にするライブラリが必要だと思います(IOコード全体を自分で記述したい場合を除く)。
頭に浮かぶ2つは次のとおりです。
Files.write(stringData, file, Charsets.UTF_8);
FileUtils.writeStringToFile(file, stringData, "UTF-8");
使用しているNiceライブラリを見つけました。
http://sourceforge.net/apps/trac/ffpojo/wiki
XMLまたは注釈を使用して構成するのは非常に簡単です!
フレームワークについてはわかりませんが、RandomAccessFileを使用できます。ファイルポインタをファイル内の任意の場所に配置して、読み取りと書き込みを行うことができます。