Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème concaténation fichiers xlsx

    11 septembre 2019 à 13:57:50

    Bonjour à tous,

    J'ai besoin, pour un projet, de concaténer plusieurs fichiers xlsx possédant plusieurs onglets en un seul fichier xlsx (contenant le même nombre d'onglets).

    Voilà le code :

    import java.io.Closeable;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.xssf.usermodel.XSSFCell;
    import org.apache.poi.xssf.usermodel.XSSFCellStyle;
    import org.apache.poi.xssf.usermodel.XSSFRow;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter;
    
    public class ExcelData4 {
    
    	private static int passage = 0;		// =0 si on lit le 1er fichier (permet de récupérer l'en-tete mais pas pour les autres fichiers où "passage" sera incrémenté de 1)
    	private static int nbreLigneEntete; // nombre de lignes de l'en-tête avant que l'on arrive sur une ligne de données
    	
    	//chemins modifiables via UI.java
    	private static String directoryName;
    	private static String outputPath;
    	
    	//check si la concatéation est ok!
    	private static boolean isCorrect;
    	
    	public static void mergeExcelFiles(File file) throws IOException
    	{
    		XSSFWorkbook book = new XSSFWorkbook();
    		System.out.println(file.getName());
    		//chemin où se trouvent les fichiers à concatener
    //		setDirectoryName("C:/Users/S0079235/Desktop/JSConcatenate/mensuel/");
    		File directory = new File(getDirectoryName());
    		//on récupère tous les fichiers du dossier
    		File[] fList = directory.listFiles();
    		
    		//pour chacun des fichiers récupérés
    		for(File file1 : fList)
    		{
    			if(file1.isFile())
    			{		
    				String ParticularFile = file1.getName();
    				FileInputStream fin = new FileInputStream(new File(getDirectoryName()+"\\"+ParticularFile));
    				XSSFWorkbook b = new XSSFWorkbook(fin);
    				
    				//pour tout les onglets du fichier excel
    				for(int i = 0; i < b.getNumberOfSheets(); i++)
    				{
    					XSSFSheet sheet;
    
    					System.out.println("Sheet name : " + b.getSheetName(i));	
    					sheet = book.getSheet(b.getSheetName(i));
    					
    					//si le nom de l'onglet n'existe pas encore, on le creait
    					if(sheet == null)
    						sheet = book.createSheet(b.getSheetName(i));
    					
    					//sinon on le copie dans celui existant
    					copySheets(book, sheet, b.getSheetAt(i));
    					System.out.println("Copie en cours....");
    					
    					//on supprime les lignes vides
    					removeEmptyRows(sheet);
    					
    					//on fusionne les cellules de l'en-tete
    					sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 10));	
    					
    					//on incorpore le filtre sur la colonne des noms 
    
    				}
    				
    				passage++;
    				
    			}
    			
    			try
    			{
    				writeFile(book, file);
    			}
    			catch(Exception e)
    			{
    				e.printStackTrace();
    			}
    			
    		}
    		
    		System.out.println("Fichier correctement constitué");
    		setCorrect(true);
    	}
    	
    	protected static void writeFile(XSSFWorkbook book, File file) throws Exception
    	{
    		FileOutputStream out = new FileOutputStream(file);
    		book.write(out);
    		out.close();
    	}
    	
    	private static void copySheets(XSSFWorkbook newWorkbook, XSSFSheet newSheet, XSSFSheet sheet)
    	{
    		copySheets(newWorkbook, newSheet, sheet, true);
    	}
    	
    	private static void copySheets(XSSFWorkbook newWorkbook, XSSFSheet newSheet, XSSFSheet sheet, boolean copyStyle)
    	{
    		int newRowNumber = newSheet.getLastRowNum();
    		int maxColumnNum = 0;
    		Map<Integer, XSSFCellStyle> styleMap = (copyStyle) ? new HashMap<Integer, XSSFCellStyle>() : null;
    		
    		//on positionne la valeur 6 sur la variable cnt si "passage" n'est pas égal à zero. La valeur 6 correspond au nombres de lignes de l'en-tête + nom des colonnes
    		nbreLigneEntete = 0;
    		if(passage != 0)
    			nbreLigneEntete = 6;
    	
    		//si cnt n'est pas égal à 0, et donc que nous avons déjà copié l'en-tête pour le premier fichier trouvé, nous copions toutes les lignes sauf l'en-tête (la première ligne)
    		for(int i = sheet.getFirstRowNum() + nbreLigneEntete; i <= sheet.getLastRowNum(); i++)
    		{
    			XSSFRow srcRow = sheet.getRow(i);
    			XSSFRow destRow = newSheet.createRow(i + newRowNumber);
    			
    			if(srcRow != null)
    			{
    				copyRow(newWorkbook, sheet, newSheet, srcRow, destRow, styleMap);
    
    				if(srcRow.getLastCellNum() > maxColumnNum)
    				{
    					maxColumnNum = srcRow.getLastCellNum();
    				}
    			}
    		}
    		
    		for(int i = 0; i <= maxColumnNum; i++)
    		{
    			newSheet.setColumnWidth(i, sheet.getColumnWidth(i));
    		}
    		
    	}
    	
    	public static void copyRow(XSSFWorkbook newWorkbook, XSSFSheet srcSheet, XSSFSheet destSheet, XSSFRow srcRow, XSSFRow destRow, Map<Integer, XSSFCellStyle> styleMap)
    	{
    		destRow.setHeight(srcRow.getHeight());
    		
    		for(int j = srcRow.getFirstCellNum(); j <= srcRow.getLastCellNum(); j++)
    		{
    			XSSFCell oldCell = srcRow.getCell(j);
    			XSSFCell newCell = destRow.getCell(j);
    			if(oldCell != null)
    			{
    				if(newCell == null)
    				{
    					newCell = destRow.createCell(j);
    				}
    				
    				copyCell(newWorkbook, oldCell, newCell, styleMap);
    			}
    		}
    	}
    	
    	public static void copyCell(XSSFWorkbook newWorkbook, XSSFCell oldCell, XSSFCell newCell, Map<Integer, XSSFCellStyle> styleMap)
    	{
    		if(styleMap != null)
    		{
    			int stHashCode = oldCell.getCellStyle().hashCode();
    			XSSFCellStyle newCellStyle = styleMap.get(stHashCode);
    			
    			if(newCellStyle == null)
    			{
    				newCellStyle = newWorkbook.createCellStyle();
    				newCellStyle.cloneStyleFrom(oldCell.getCellStyle());
    				styleMap.put(stHashCode, newCellStyle);
    			}
    			
    			newCell.setCellStyle(newCellStyle);
    		}
    		
    		 switch (oldCell.getCellType()) {
             case XSSFCell.CELL_TYPE_FORMULA:
                 newCell.setCellFormula(oldCell.getCellFormula());
                 break;
             case XSSFCell.CELL_TYPE_NUMERIC:
            	 newCell.setCellValue(oldCell.getNumericCellValue());
                 break;
             case XSSFCell.CELL_TYPE_STRING:
            	 newCell.setCellValue(oldCell.getStringCellValue());
                 break;
             case XSSFCell.CELL_TYPE_BLANK:
            	 newCell.setCellType(XSSFCell.CELL_TYPE_BLANK);
                 break;
             case XSSFCell.CELL_TYPE_BOOLEAN:
            	 newCell.setCellValue(oldCell.getBooleanCellValue());
                 break;
             case XSSFCell.CELL_TYPE_ERROR:
            	 newCell.setCellErrorValue(oldCell.getErrorCellValue());
                 break;
             default:
                 break;
    		 }
    		
    	}
    	
    	private static void removeEmptyRows(XSSFSheet sheet) {
    	    Boolean isRowEmpty = Boolean.FALSE;
    	    for(int i = 0; i <= sheet.getLastRowNum(); i++){
    	      if(sheet.getRow(i)==null){
    	        isRowEmpty=true;
    	        sheet.shiftRows(i + 1, sheet.getLastRowNum()+1, -1);
    	        i--;
    	        continue;
    	      }
    	      for(int j =0; j<sheet.getRow(i).getLastCellNum();j++){
    	        if(sheet.getRow(i).getCell(j) == null || 
    	        sheet.getRow(i).getCell(j).toString().trim().equals("")){
    	          isRowEmpty=true;
    	        }else {
    	          isRowEmpty=false;
    	          break;
    	        }
    	      }
    	      if(isRowEmpty==true){
    	        sheet.shiftRows(i + 1, sheet.getLastRowNum()+1, -1);
    	        i--;
    	      }
    	    }
    	  }
    	
    	public static String getDirectoryName() {
    		return directoryName;
    	}
    
    	public static void setDirectoryName(String directoryName) {
    		ExcelData4.directoryName = directoryName;
    	}
    
    	public static String getOutputPath() {
    		return outputPath;
    	}
    
    	public static void setOutputPath(String outputPath) {
    		ExcelData4.outputPath = outputPath;
    	}
    
    	public static boolean getIsCorrect() {
    		return isCorrect;
    	}
    
    	public static void setCorrect(boolean isCorrect) {
    		ExcelData4.isCorrect = isCorrect;
    	}
    }

    Ce programme est appelé par une interface utilisateur dont voici le code :

    import java.awt.*;
    import java.awt.event.*;
    import java.io.File;
    import java.io.IOException;
    
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.ProgressMonitor;
    import javax.swing.SwingWorker;
    
    public class UI extends Frame implements ActionListener, WindowListener {
    
    	private Label inputDir;    // Repertoire emplacement des fichiers à concatener 
    	private Label outputDir;    // Repertoire du fichier généré en sortie 
    	private TextField tfCountInput, tfCountOutput; // Declare a TextField component 
    	private Button btnCount;   // Declare a Button component
    	private Label checkControle; // bouton indiquant le bon ou mauvais deroulement du traitement
    	private String inputPath = "";     // Counter's value
    	private String outputPath = "";     // Counter's value
    	
    	private String cheminInput, cheminOutput;
    	private String moisDebut, moisFin;
    	private String anneeDebut, anneeFin;
    	
    	private JFileChooser parcourirInput;
    	
    	public UI()
    	{
    		setLayout(new FlowLayout());
    
    		//section chemin des fichiers à concatener
    		inputDir = new Label("Emplacement des fichiers : ");
    		add(inputDir);
    		
    		//nom du chemin (possibilité de le renseigner à la main)
    		tfCountInput = new TextField(50);
    		tfCountInput.setEditable(true);
    		add(tfCountInput);
    
    		//parcourir
    		JButton b1 = new JButton("parcourir...");
    		add(b1);
    		b1.addActionListener(new ActionListener()
    		{
    			@Override
    			public void actionPerformed(ActionEvent e)
    			{
    				parcourirInput = new JFileChooser();
    				parcourirInput.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
    				parcourirInput.showOpenDialog(null);
    				inputDir.setAlignment(Label.LEFT);
    				
    				inputPath = parcourirInput.getSelectedFile().getPath();
    				System.out.println("chemin : " + inputPath);
    				tfCountInput.setText(inputPath + "");
    				ExcelData4.setDirectoryName(inputPath);
    			}
    		});
    			
    		//section chemin du fichier généré
    		outputDir = new Label("merged.xlsx : ");
    		add(outputDir);
    		
    		//nom du chemin (renseignable)
    		tfCountOutput = new TextField(50);
    		tfCountOutput.setEditable(true);
    		add(tfCountOutput);
    		
    		//parcourir
    				JButton b2 = new JButton("parcourir...");
    				add(b2);
    				b2.addActionListener(new ActionListener()
    				{
    					@Override
    					public void actionPerformed(ActionEvent e)
    					{
    						parcourirInput = new JFileChooser();
    						parcourirInput.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
    						parcourirInput.showOpenDialog(null);
    						inputDir.setAlignment(Label.LEFT);
    						
    						outputPath = parcourirInput.getSelectedFile().getPath();
    						System.out.println("chemin : " + outputPath);
    						tfCountOutput.setText(outputPath + "");
    						ExcelData4.setOutputPath(outputPath);
    					}
    				});
    		
    		setTitle("Concaténation fichiers xlsx");
    		setSize(800, 400);
    		setVisible(true); 
    		
    		btnCount = new Button("Concatener");
    		add(btnCount);
    		btnCount.addActionListener(this);
    
    		addWindowListener(this);
    		
    		//bouton de controle pour voir si ça s'est bien passé
    		checkControle = new Label("Resultat");
    		add(checkControle);
    		
    	}
    	
    	
    	public static void main(String[] args) 
    	{
    		 new UI();
    	}
    	
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		// TODO Auto-generated method stub
    
    		try 
    		{
    			ExcelData4.mergeExcelFiles(new File(outputPath + "/merged.xlsx"));
    			//Mise en forme du fichier de sortie
    //			JSMisEnForme.miseEnForme(outputPath);
    			
    		} catch (Exception e1) {
                e1.printStackTrace();
    		} 
    	}
    	
    	@Override
    	public void windowClosing(WindowEvent evt)
    	{
    		System.exit(0);
    	}
    
    	@Override
    	public void windowOpened(WindowEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void windowClosed(WindowEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void windowIconified(WindowEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void windowDeiconified(WindowEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void windowActivated(WindowEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    
    	@Override
    	public void windowDeactivated(WindowEvent e) {
    		// TODO Auto-generated method stub
    		
    	}
    
    }
    

    Le code s'effectue correctement mais à l'ouverture du fichier excel généré (merged.xlsx), ce message apparait :

    "Désolé... Nous avons trouvé un problème dans le contenu de "merged.xlsx", mais nous pouvons essayer de récupérer le maximum de contenu. Si la source de ce classeur est fiable, cliquez sur Oui."

    Je clique sur oui et un autre message apparait :

    Enregistrements supprimés: Fusionner les cellules dans la partie /xl/worksheets/sheet1.xml

    Enregistrements supprimés: Fusionner les cellules dans la partie /xl/worksheets/sheet2.xml

    Enregistrements supprimés: Fusionner les cellules dans la partie /xl/worksheets/sheet3.xml

    Enregistrements supprimés: Fusionner les cellules dans la partie /xl/worksheets/sheet4.xml

    Enregistrements réparés: Format dans la partie /xl/styles.xml (Styles)

    Il semble y avoir un problème de style car le style des fichiers à concaténer n'est pas récupéré. En me renseignant, il apparaitrait que le nombre de style soit trop important...

    Quelqu'un.e aurait une solution pour contourner ce problème ? 

    En me rendant compte qu'en enregistrant le fichier excel "corrompu" sous un autre nom une fois ouvert, ce message n'apparaissait plus.

    Y a t'il un moyen via JAVA d'effectuer le même processus afin de générer un fichier final n'ayant pas ce message d'erreur lié au style ?

    Cordialement,

    • Partager sur Facebook
    • Partager sur Twitter

    Problème concaténation fichiers xlsx

    × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
    × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
    • Editeur
    • Markdown