IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Documents Java Discussion :

Merger des documents word (docx) en Java


Sujet :

Documents Java

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2016
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Merger des documents word (docx) en Java
    Bonjour,
    je suis confronté à un problème dans un projet depuis plusieurs jours et j’espère trouver de l'aide sur ce forum.

    J'essaye de créer une fonction en java (je développe sous Eclipse) qui permet de fusionner différents documents Word pour n'en faire qu'un seul, cela s’apparenterait à copier les documents (contenu + mise en page) le uns à la suite des autres.

    J'ai donc écrit le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class Main {
    	public static void main(String[] args) throws Exception {
    		//Liste des numéro des documents que je souhaite "merger"
     
                    ArrayList<String> Op= new ArrayList<String>();
    		Op.add("1");
    		Op.add("2");
    		Op.add("3");
     
    		//Fichier contenant le document final, si il existe déjà on le supprime afin d'en créer un nouveau et éviter des problème de sur-écriture
    		File sortie = new File("Devis.doc");
    		if(sortie.exists()==true){
    			sortie.delete();
    			System.out.println("Delete previous Devis\n");
    		}
     
    		//On prépare la première page à devoir être copie et l’endroit où on doit la coller
    		//L'argument true dans fos permet "normalement" de copier les données à la suite du document si il y a déjà des données présentent
     
                    File entre = new File("page"+Op.get(0)+".doc");
    		FileOutputStream fos = new FileOutputStream(sortie, true);
    		BufferedOutputStream bos = new BufferedOutputStream(fos);
     
    		//On appelle la fonction qui effectue l'opération
    		merge(Op, entre, bos);
    		//On ferme le BufferedOutputStream
                    bos.close();
    Voici maintenant la fonction "merge"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    private static void merge(ArrayList<String> Op, File entre, BuffredOutputStream bos) throws IOException{
    		if(Op.size() == 0)
    			return;
    		else{
    			byte[] buffer = new byte[8];
    			//On prépare le fichier en entre
    			FileInputStream fis = new FileInputStream(entre);
    			BufferedInputStream bis = new BufferedInputStream(fis);
     
    			//Tant qu'il reste des données (donc code de retour différent de -1), 
    			//on doit continuer à copier dans le fichier de sortie
    			int numBytes = bis.read(buffer);
    			try{
    				while(numBytes != -1){
    					bos.write(buffer, 0, numBytes);
    					numBytes = bis.read(buffer);
    				}
     
    				bos.write(13); //Ajout d'un saut de ligne
    				bos.write(10); //Ajout d'un retour chariot
    				System.out.println("Copie de "+Op.get(0)+" dans fichier Devis");
    				bos.flush();
    				bis.close();
    				bos.close();
    			}catch (IOException e){
    				e.printStackTrace();
    			}
     
    			//Une fois la page copier on la supprime de la liste des pages à copier
    			//Si la liste n'est pas vide => Il y a d'autre page à copier donc on prepare la page suivante
    			//et on rappel la fonction qui effectura l'opération
    			Op.remove(0);
                            if(Op.size()!=0){
    				entre = new File("page"+Op.get(0)+".doc");
    				merge(Op, entre, sortie);
    			}
    		}
    	}
    Avec cette fonction j'arrive à copier l'ensemble des octets qui compose les différents documents (le document final a pour taille la somme d'octets des différents document fusionnés) mais quand j'ouvre ce document final, seul le premier document apparait (contenu + mise en page).
    A noter que si j'ouvre ce document final dans un éditeur de texte (style WordPad), j'arrive à voir les autres documents (contenu et la mise en page apparait sous forme de symboles divers).

    Si l'un d'antre vous à une solution et/ou idée pour m'aider à résoudre ce problème, merci d'avance.

    Ps: J'ai essayé des solutions via des API comme POI ou Docx4j mais le résultat est soit le même que celui décris au dessus, soit je n'obtient qu'un document final corrompus. Si jamais vous avez une solution reposant sur ces API, je suis tout aussi preneur, merci

  2. #2
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Salut,

    Le format des fichiers word (DOC ou DOCX) ne permet pas de juste mettre bout à bout les flux et que ça fonctionne : ce n'est pas juste du texte, il y a des headers, un syntaxe particulière, etc. C'est un coup de bol que Word t'affiche que la première page (ça vient du format qui contient au début des headers avec un nombre de blocs (en gros une taille de doc) qui fait que ça ignore tout ce qu'il y a après. Avec du docx, tu te retrouverais avec 2 fichiers xml (donc 2 root elements) bout à bout, peu de chance que ça ne soit pas rejeté par un parser xml.

    La bonne méthode, c'est d'utiliser une API qui traite le format. Il n'y a pas de raison que la fusion avec POI donne un fichier corrompu. Il y a possiblement des bugs dans POI, mais le problème vient plus probablement de ton code. Montre-le nous.
    L'expression "ça marche pas" ne veut rien dire. Indiquez l'erreur, et/ou les comportements attendus et obtenus, et donnez un Exemple Complet Minimal qui permet de reproduire le problème.
    La plupart des réponses à vos questions sont déjà dans les FAQs ou les Tutoriels, ou peut-être dans une autre discussion : utilisez la recherche interne.
    Des questions sur Java : consultez le Forum Java. Des questions sur l'EDI Eclipse ou la plateforme Eclipse RCP : consultez le Forum Eclipse.
    Une question correctement posée et rédigée et vous aurez plus de chances de réponses adaptées et rapides.
    N'oubliez pas de mettre vos extraits de code entre balises CODE (Voir Mode d'emploi de l'éditeur de messages).
    Nouveau sur le forum ? Consultez Les Règles du Club.

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2016
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Bonjour, d'abord merci de votre aide.

    Voici ce que j'ai fait avec l'API POI:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    XWPFDocument document = new XWPFDocument();
     
    		FileInputStream fis = new FileInputStream("page1.docx");
    		XWPFDocument doc = new XWPFDocument(fis);
    		org.apache.poi.xwpf.extractor.XWPFWordExtractor oleTextExtractor = new XWPFWordExtractor(doc);
     
    		FileInputStream fis2 = new FileInputStream("page2.docx");
    		XWPFDocument doc2 = new XWPFDocument(fis2);
    		org.apache.poi.xwpf.extractor.XWPFWordExtractor oleTextExtractor2 = new XWPFWordExtractor(doc2);
     
    		XWPFParagraph tmpParagraph = document.createParagraph();
    		XWPFRun tmpRun = tmpParagraph.createRun();
    		tmpRun.setText(oleTextExtractor.getText());
    		System.out.print(oleTextExtractor.getText());
     
    		XWPFParagraph tmpParagraph2 = document.createParagraph();
    		XWPFRun tmpRun2 = tmpParagraph2.createRun();
    		tmpRun2.setText(oleTextExtractor2.getText());
    		System.out.print(oleTextExtractor2.getText());
     
    		FileOutputStream file = new FileOutputStream("res.docx", true);
    		document.write(file);
    		file.close();
    		System.out.println("success");
    Je sais par avance que ce que j'ai fait permet uniquement de récupérer le texte des différent documents.
    Suis-je sur la bonne voie, est ce que je n'ai plus qu'a rajouté ce qui ressemblerai à des get header footer etc.. ou suis je complétement à côté?
    Merci

    ps: je sais que l'on doit utilisé XWPF pour les docx et HWPF pour les doc, si jamais il faut privilégier l'un des deux, cela ne pose pas de problème.

  4. #4
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2016
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Re-bonjour,
    n'ayant pas réussi à développer une solution avec POI, je me suis lancé dans une solution avec AltChunk.
    En me basant sur des travaux trouvé sur le net, voici ce que j'ai conçu:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
           public class Main {
    	public static void main(String[] args) throws Exception {         
                    FileInputStream entre2 = new FileInputStream(new File("page1.docx"));
    		FileInputStream entre3 = new FileInputStream(new File("page2.docx"));
     
    		ArrayList<InputStream> liste = new ArrayList<InputStream>();
    		liste.add(entre2);
    		liste.add(entre3);
    		mergeDocx(liste);
    	}
     
    	private static final String CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
     
    	private static InputStream mergeDocx(final List<InputStream> streams) throws Docx4JException, IOException {
     
    		WordprocessingMLPackage target = null;
    		final File generated = File.createTempFile("generated", ".docx");
     
    		int chunkId = 0;
    		Iterator<InputStream> it = streams.iterator();
    		while (it.hasNext()) {
    			InputStream is = it.next();
    			if (is != null) {
    				if (target == null) {
    					// Copy first (master) document
    					OutputStream os = new FileOutputStream(generated);
    					os.write(IOUtils.toByteArray(is));
    					os.close();
     
    					target = WordprocessingMLPackage.load(generated);
    				} else {
    					// Attach the others (Alternative input parts)
    					insertDocx(target.getMainDocumentPart(), IOUtils.toByteArray(is), chunkId++);
    				}
    			}
    		}
     
    		if (target != null) {
    			target.save(generated);
    			return new FileInputStream(generated);
    		} else {
    			return null;
    		}
    	}
     
    	private static void insertDocx(MainDocumentPart main, byte[] bytes, int chunkId) {
    		try {
    			AlternativeFormatInputPart afiPart = new AlternativeFormatInputPart(new PartName("/part" + chunkId + ".docx"));
    			afiPart.setContentType(new ContentType(CONTENT_TYPE));
    			afiPart.setBinaryData(bytes);
    			Relationship altChunkRel = main.addTargetPart(afiPart);
     
    			CTAltChunk chunk = Context.getWmlObjectFactory().createCTAltChunk();
    			chunk.setId(altChunkRel.getId());
     
    			main.addObject(chunk);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    J'ai encore des erreurs de librairies, j'ai importer: org.eclipse.persistance.core.jar et org.eclipse.persistance.moxy.jar et j'ai le message suivant: Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/persistence/internal/libraries/asm/ClassWriter

    Si quelqu'un a une idée pour se problème ou une solution me permettant de merger des documents words (docx) à base de AltChunk ou d'autre chose, qu'il n'hésite pas, Merci d'avance.

  5. #5
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 934
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 934
    Points : 4 347
    Points
    4 347

  6. #6
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Septembre 2016
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Aube (Champagne Ardenne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Septembre 2016
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Bonjour,
    j'ai déjà essayer de travailler avec docx4j mais je n'obtient pas les résultats que je souhaite.
    J'ai discuté avec des développeur qui travaillent sur ces API et ils m'ont dis que faire la fusion de documents Word en java avec ces API là est quasiment impossible car il y aurai des éléments qui seraient impossible à copier (notamment au niveau du XML).

    Je vais donc passer sur l'API Aspose Word for Java, j'ai déjà fais des tests avec la version d’évaluation et les résultats correspondent parfaitement à mes attente.

    Je conçois qu'il s'agit d'un API payante mais elle est très simple d'utilisation et elle offre beaucoup d'autres fonctionnalités qui pourraient m'être utile dans mes futurs projets.

    Je vous remercie de votre aide et je marque le sujet comme résolu.

    Je précise pour les autres visiteurs de cette discussion que les API POI et Docx4j offre de nombreuses possibilité pour faire de la dev java en lien avec Word (et même excel) mais elles sont limitées quand on veut faire des choses plus complexe que juste copier du texte, une image ou change le font du Word.

    Cordialement

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Créer des documents Word en Java
    Par Aure7780 dans le forum Documents
    Réponses: 23
    Dernier message: 01/08/2011, 02h19
  2. Réponses: 17
    Dernier message: 01/10/2007, 12h05
  3. Copier des documents word l'un dans l'autre | OleWord
    Par madnux dans le forum C++Builder
    Réponses: 12
    Dernier message: 20/05/2007, 12h58
  4. Réponses: 8
    Dernier message: 04/04/2007, 20h38
  5. Réponses: 11
    Dernier message: 26/04/2005, 10h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo