Question

Existe-t-il un framework / bibliothèque pour aider à écrire des fichiers plats de longueur fixe en java?

Je veux écrire une collection de beans / entités dans un fichier plat sans me soucier des conversions, du remplissage, de l'alignement, des remplissages, etc.

Par exemple, j'aimerais analyser un bean comme:

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
}

... dans ...

name      123  0032120110505
mikhas    5000 0122120110504
superuser 1    0000120101231

...

Était-ce utile?

La solution

Si vous êtes toujours à la recherche d'un framework, consultez BeanIO sur http://www.beanio.org

Autres conseils

Il est peu probable que vous rencontriez un framework capable de gérer le format d'un système "Legacy". Dans la plupart des cas, les systèmes hérités n'utilisent pas de formats standard, mais les frameworks les attendent. En tant que mainteneur des systèmes COBOL hérités et de la conversion Java / Groovy, je rencontre fréquemment cette incohérence. «S'inquiéter des conversions, du remplissage, de l'alignement, des charges, etc.» est principalement ce que vous faites lorsque vous traitez avec un système hérité. Bien sûr, vous pouvez en encapsuler une partie dans des aides pratiques. Mais très probablement, vous aurez besoin de vous familiariser avec java.util.Formatter.

Par exemple, vous pouvez utiliser le modèle Décorateur pour créer des décorateurs pour effectuer la conversion. Voici un peu de groovy (facilement convertible en 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'

Ceci est réalisable si vous n'en avez pas trop et que les objets ne sont pas trop complexes. Mais assez rapidement, la chaîne de format devient intolérable. Ensuite, vous voudrez peut-être des décorateurs pour Date, comme:

class DateYMD {
     Date d
     DateYMD(d) { this.d = d }
     String toString() { return d.format('yyyyMMdd') }
 }

pour que vous puissiez formater avec% s:

    String asRecord() {
         return String.format('%-10s%-5d%05d%s',
                               d.name,d.id,d.serial,new DateYMD(d.register))
   }

Mais pour un nombre important de propriétés de bean, la chaîne est encore trop grossière, vous voulez donc quelque chose qui comprend les colonnes et les longueurs qui ressemble à la spécification COBOL qui vous a été remise, vous allez donc écrire quelque chose comme ceci:

 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()
     }

}

Après avoir écrit suffisamment de méthodes setField () pour gérer votre ancien système, vous envisagerez brièvement de le publier sur GitHub en tant que «framework» pour que le prochain pauvre sap ne doive pas le refaire. Mais alors vous considérerez toutes les façons ridicules dont vous avez vu COBOL stocker une "date" (MMJJAA, AAMMJJ, AAJJJ, AAAAJJJ) et des chiffres (décimale supposée, décimale explicite, signe comme séparé à la fin ou signe comme premier caractère flottant). Ensuite, vous comprendrez pourquoi personne n'a produit un bon framework pour cela et publiez occasionnellement des morceaux de votre code de production dans SO à titre d'exemple ...;)

uniVocity-parsers permet de prendre en charge des formats complexes à largeur fixe, y comprislignes avec différents champs, rembourrages, etc.

Consultez cet exemple pour écrire des détails imaginaires sur le client et les comptesCela utilise une valeur d'anticipation pour identifier le format à utiliser lors de l'écriture d'une ligne:

    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());

Le résultat sera:

C#___000000000023234Miss Foo____________
A#23234___HSBC____123433-000_____HSBCAUS_____
A#234_____HSBC____222343-130_____HSBCCAD_____
C#___000000000000322Mr Bar______________
A#1234____CITI____213343-130_____CITICAD_____

Ceci n'est qu'un exemple approximatif.Il existe de nombreux autres options disponibles , y compris la prise en charge des beans java annotés, que vous pouvez trouver ici .

Divulgation: je suis l'auteur de cette bibliothèque, elle est open-source et gratuite (licence Apache 2.0)

Spring Batch a une FlatFileItemWriter , mais cela ne vous aidera que si vous utilisez l'ensembleAPI Spring Batch.


Mais à part cela, je dirais que vous avez juste besoin d'une bibliothèque qui facilite l'écriture dans des fichiers (à moins que vous ne vouliez écrire vous-même tout le code IO).

Deux qui me viennent à l'esprit sont:

Goyave

Files.write(stringData, file, Charsets.UTF_8);

Commons / IO

FileUtils.writeStringToFile(file, stringData, "UTF-8");

La bibliothèque Fixedformat4j est un outil très intéressant pour faire exactement cela: http://fixedformat4j.ancientprogramming.com/

Je ne connais aucun cadre mais vous pouvez simplement utiliser RandomAccessFile.Vous pouvez positionner le pointeur de fichier n'importe où dans le fichier pour effectuer vos lectures et vos écritures.

Je viens de trouver une jolie bibliothèque que j'utilise:
http://sourceforge.net/apps/trac/ffpojo/wiki

Très simple à configurer avec XML ou des annotations!

Un moyen simple d'écrire des beans / entités dans un fichier plat consiste à utiliser ObjectOutputStream.

public static void writeToFile(File file, Serializable object) throws IOException {
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
    oos.writeObject(object);
    oos.close();
}

Vous pouvez écrire dans un fichier plat de longueur fixe avec

FileUtils.writeByteArrayToFile(new File(filename), new byte[length]);

Vous devez être plus précis sur ce que vous voulez faire avec le fichier.;)

Essayez l'API FFPOJO car elle contient tout ce dont vous avez besoin pour créer un fichier plat avec des longueurs fixes etil convertira également un fichier en objet et vice versa.

@PositionalRecord
public class CFTimeStamp {

    String timeStamp;

    public CFTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }

    @PositionalField(initialPosition = 1, finalPosition = 26, paddingAlign = PaddingAlign.RIGHT, paddingCharacter = '0')
    public String getTimeStamp() {
        return timeStamp;
    }

    @Override
    public String toString() {
        try {
            FFPojoHelper ffPojo = FFPojoHelper.getInstance();
            return ffPojo.parseToText(this);
        } catch (FFPojoException ex) {
            trsLogger.error(ex.getMessage(), ex);
        }
        return null;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top