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,
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.