Créer tableau uniforme dans un fichier Texte (JAVA)

Résolu
skold Messages postés 6 Date d'inscription samedi 11 décembre 2004 Statut Membre Dernière intervention 31 juillet 2011 - 22 mai 2011 à 11:07
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 - 23 mai 2011 à 10:05
Bonjour tous le monde.

J'aimerai créer un tableau (en ascii) dans un fichier texte du style :
CONTEXT                       |TRAITE         |A_APPLIQUER    |
--------------------------------------------------------------|
1erContexte                   |20             |5              |
2eContexte                    |20             |5              |
3eContexte                    |205400000000000|5              |
4eContexte                    |8              |511454152121211|
5eContexteTresLonggggggggggggg|8              |511454152121211|


Pour cela je dispose d'une classe StatsActes que j'ai créé:
public class StatsActes {

private String contexte;
private String etat;
private String nombre;
//Je vous épargne mes getters et setters.
}


Sur une requête en base, je récupère une List<StatsActes>, puis je la transforme en HashMap<String, Set<StatsActes>> pour trier tout ceci par contexte.

HashMap<String, Set<StatsActes>> map = new HashMap<String, Set<StatsActes>>();
  
        for (StatsActes stats : statsActes) {
            String context = stats.getContexte();
            Set<StatsActes> sa = new HashSet<StatsActes>();
            sa.add(stats);
            if(!map.containsKey(context)){
                map.put(context, sa);
              }
               else{
                   map.get(context).add(stats);
               }
        }


Ce que j'aimerai, c'est créer mon tableau comme ci dessus mais en tenant compte de la longueur des mes champs pour avoir un tableau uniforme pour pouvoir lire mon fichier correctement et pas chercher la colonne comme du genre :
CONTEXT|TRAITE|A_APPLIQUER|
--------------------------|
1erContexte|20|5|
2eContexte|20|5|
3eContexte|205400000000000|5|
4eContexte |8|511454152121211|
5eContexteTresLonggggggggggggg|8|511454152121211|


(Je précise l'entête : CONTEXT = contexte de ma classe StatsActes, TRAITE et A_APPLIQUER sont les états que je récupère de StatsActes aussi)

Pour la création de mon fichier texte, je n'ai pas le choix, je dois utiliser les librairies standards. Personnellement j'utilise ceci :
OutputStream outputStream = new FileOutputStream(new  File("./File.txt"));
Writer writer = new OutputStreamWriter(outputStream);


Voila j'espère avoir été assez clair sur mon besoin. Si vous voulez plus d'informations n'hésitez pas! Merci d'avance à tous le monde

10 réponses

Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
23 mai 2011 à 10:05
Salut,

Si tu t'es basé sur ma méthode writeInFile l'ordre de tes champs se trouve là ou il y a les writeItem(...).



------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
3
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
22 mai 2011 à 12:01
Salut,

Pourquoi te prendre la tête avec la longueur de tes champs ?
Tu fais une lecture de ton fichier (sans les 2 premières lignes) ligne à ligne et pour chaque ligne tu utilises StringTokenizer

exemple:

fichier test.txt
CONTEXT|TRAITE|A_APPLIQUER|
--------------------------|
1erContexte|20|5|
1erContexte|30|10|
2eContexte|20|5|
3eContexte|205400000000000|5|
4eContexte |8|511454152121211|
5eContexteTresLonggggggggggggg|8|511454152121211|



Classe permettant de parser le fichier et d'afficher la table:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.StringTokenizer;

public class Test {

public static void main(final String[] args) {
final Test t = new Test();
HashMap<String, Set<StatsActes>> map = null;
try {
map = t.loadFromFile(new File("Test.txt"));
} catch (final FileNotFoundException e) {
e.printStackTrace();
}
t.print(map);
}

public HashMap<String, Set<StatsActes>> loadFromFile(final File file)
throws FileNotFoundException {
final HashMap<String, Set<StatsActes>> map = new HashMap<String, Set<StatsActes>>();
final Scanner sc = new Scanner(file);
int lines = 0; // pour ne pas traiter les 2 premieres lignes
StringTokenizer token = null; // pour parser les champs
Set<StatsActes> sa = null;
StatsActes item = null;
while (sc.hasNextLine()) {
final String line = sc.nextLine();
if (lines < 2) {
lines++;
continue;
}
token = new StringTokenizer(line, "|");
// récupération des données avec un petit test
final String context = token.hasMoreTokens() ? token.nextToken() : "Error";
final String etat = token.hasMoreTokens() ? token.nextToken() : "Error";
final String nombre = token.hasMoreTokens() ? token.nextToken() : "Error";
sa = new HashSet<StatsActes>();
// j'ai ajouté le constructeur
// public StatsActes(final String contexte, final String etat, final
// String nombre)
item = new StatsActes(context, etat, nombre);

if (!map.containsKey(context)) {
sa.add(item);
map.put(context, sa);
} else
map.get(context).add(item);
}
sc.close();
return map;
}

public void print(final HashMap<String, Set<StatsActes>> map) {
final Set<String> keys = map.keySet();
for (final String key : keys) {
System.err.println(key);
final Set<StatsActes> value = map.get(key);
for (final StatsActes v : value) {
// j'ai redef toString
// public String toString() {
// return contexte + "|" + etat + "|" + nombre;
// }
System.err.println("\tv: " + v);
}
}

}
}






------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
0
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
22 mai 2011 à 12:04
Re,

Tite coquille, la ligne "sa = new HashSet<StatsActes>();" est a placer dans le "if (!map.containsKey(context))" pour éviter l'allocation si l'item est déjà présent.





------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
0
skold Messages postés 6 Date d'inscription samedi 11 décembre 2004 Statut Membre Dernière intervention 31 juillet 2011
22 mai 2011 à 12:23
Le problème est que je n'ai pas de fichier au départ, c'est moi qui veut créer ce beau tableau.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
skold Messages postés 6 Date d'inscription samedi 11 décembre 2004 Statut Membre Dernière intervention 31 juillet 2011
22 mai 2011 à 12:24
Petit précision, ce qu'il y a dans ma List<StatsActes> est le résultat d'une requête sur une base oracle.
0
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
22 mai 2011 à 12:37
Salut,


Le problème est que je n'ai pas de fichier au départ, c'est moi qui veut créer ce beau tableau.

Bah quoi ? il est ou le pb ? tu ajoutes une méthode pour générer un fichier ayant la même structure que ton fichier d'exemple... ce qui est fait dans le print peut facilement etre remplacé par une méthode write genre:
public void writeInFile(final HashMap<String, Set<StatsActes>> map, final File file) throws FileNotFoundException {
  PrintWriter pw = new PrintWriter(file);
  pw.println("CONTEXT|TRAITE|A_APPLIQUER|");
  pw.println("--------------------------|");
  pw.flush();
  final Set<String> keys = map.keySet();
  for (final String key : keys) {
    final Set<StatsActes> value = map.get(key);
    for (final StatsActes v : value) {
      pw.println(v.toString());
      pw.flush();
    }
  }
  pw.close();
}




Petit précision, ce qu'il y a dans ma List<StatsActes> est le résultat d'une requête sur une base oracle.

Adapte le code, je ne t'ai pas donné le code ci-dessus pour te faire ton boulot mais uniquement pour te montrer les bases (principalement le StringTokenizer).


------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
0
skold Messages postés 6 Date d'inscription samedi 11 décembre 2004 Statut Membre Dernière intervention 31 juillet 2011
22 mai 2011 à 13:52
Pourquoi ce baser sur un fichier d'exemple car au stade où je veux construire mon fichier je n'ai pas de fichier d'exemple, juste ma liste. Le premier que je vous ai montré (1er de mon premier post) est le fichier que je veux avoir justement. J'ai fais des essais en parcourant la map comme toi, seulement j'obtiens le résultat suivant:

CONTEXT|TRAITE|A_APPLIQUER|
--------------------------|
1erContexte|20|5|
2eContexte|20|5|
3eContexte|205400000000000|5|
4eContexte |8|511454152121211|
5eContexteTresLonggggggggggggg|8|511454152121211|


Ce que je veux c'est que les colonnes prennent la taille maximum de mes champs pour que tout soit aligné.

Au final je veux :

CONTEXT                       |TRAITE         |A_APPLIQUER    |
--------------------------------------------------------------|
1erContexte                   |20             |5              |
2eContexte                    |20             |5              |
3eContexte                    |205400000000000|5              |
4eContexte                    |8              |511454152121211|
5eContexteTresLonggggggggggggg|8              |511454152121211|
0
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
22 mai 2011 à 14:45
Salut,

Tiens fait à l’arrache:
private enum Type {
CONTEXTE,
ETAT,
NOMBRE;
}

public void writeInFile(final HashMap<String, Set<StatsActes>> map, File file) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(file);
pw.println("CONTEXT|TRAITE|A_APPLIQUER|");
pw.println("--------------------------|");
pw.flush();
int space_context = getMax(map, Type.CONTEXTE);
int space_etat = getMax(map, Type.ETAT);
int space_nb = getMax(map, Type.NOMBRE);
final Set<String> keys = map.keySet();
for (final String key : keys) {
final Set<StatsActes> value = map.get(key);
for (final StatsActes v : value) {
writeItem(pw, v.getContexte(), space_context);
writeItem(pw, v.getEtat(), space_etat);
writeItem(pw, v.getNombre(), space_nb);
pw.println();
pw.flush();
}
}
pw.close();
}

private void writeItem(PrintWriter pw, String input, int max) {
if(input.length() < max) {
pw.print(input);
pw.print(getSpaces(max - input.length()));
pw.print(" |");
} else
pw.print(input + " |");
}

private String getSpaces(int nb) {
String ret = "";
for(int i = 0; i < nb; ++i)
ret += " ";
return ret;
}

private int getMax(final HashMap<String, Set<StatsActes>> map, Type type) {
final Set<String> keys = map.keySet();
int len = 0;
for (final String key : keys) {
final Set<StatsActes> value = map.get(key);
for (final StatsActes v : value) {
switch(type) {
case CONTEXTE:
if(v.getContexte().length() > len) len = v.getContexte().length();
break;
case ETAT:
if(v.getEtat().length() > len) len = v.getEtat().length();
case NOMBRE:
if(v.getNombre().length() > len) len = v.getNombre().length();
}
}
}
return len;
}



C'est juste pour le principe, mais il va de soit que ce codes n'est absolument pas viable dans le cas ou tu as un très grand nombre d'entrées et idéalement il faudrait que les compteurs space_xxx soient automatiquement renseignés au moment de ta lecture de base afin de gagner énormément de temps.
Ensuite vu que j'utilise un espace, si le viewer n'a pas de font monospace il y aura un décalage, cela dit tu peux remplacer les espaces par \t mais la encore ça dépend du viewer... exemple sous eclipse tu peux redef le nb d'espaces max que représente une tab.



------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
0
skold Messages postés 6 Date d'inscription samedi 11 décembre 2004 Statut Membre Dernière intervention 31 juillet 2011
22 mai 2011 à 19:08
C'est pas tout à fait ce que je veux mais cela m'aide beaucoup! Je vais partir de ton bout de code pour le continuer. Merci beaucoup!
0
skold Messages postés 6 Date d'inscription samedi 11 décembre 2004 Statut Membre Dernière intervention 31 juillet 2011
23 mai 2011 à 09:11
Le problème est que le nombre que je récupère n'est pas forcément au bon endroit (dans la bonne colonne). Aujourd'hui je suis à ce stade :

CONTEXTE          |ENREGISTRE |TRAITE |FINALISE |A_INFORMER |
SIREN_0_IMM       |2 |
MAINTOFFRES_2_CYC |1 |
MAINTPRS_1_IMM    |1 |
SIREN_2_IMM       |1 |
MAINTOFFRES_1_IMM |1 |
SIREN_1_IMM       |1 |
MAINTOFFRES_2_EFF |1 |
MAINTOFFRES_2_IMM |2 |



Le nombre en gras par exemple ne doit pas ce trouver dans la colonne enregistrer, mais dans finaliser. Il y a un histoire de position mais je suis un peux perdu.
0
Rejoignez-nous