Přeskočit na hlavní obsah

Jak na Excel 5 - knihovna JExcelApi

Konečně se v našem seriálu dostáváme k čistě javovým implemtacím Excelového formátu. Začneme knihovnou Java Excel API (JExcelApi), kterou vytvořil Andy Khan a uvolnil pod licencí GNU LGPL.

Co tato knihovna umí zajímavého?

  • vytváření a čtení XLS souborů
  • formátování buněk
  • práci se vzorci
  • vkládání PNG obrázků
  • kopírování grafů (vytváření nových podporováno není)
Knihovna není nijak rozsáhlá, takže se dá v API pohodlně orientovat.

Zajímavější pro vás může být informace, co mi na této knihovně vadí. Tady jsou mé připomínky:

  • odlišný přístup k dokumentům při čtení a při zápisu (třídy Workbook a WritableWorkbook nemají ani společný interface)
  • práce s čisly podporuje pouze typ double, osobně bych uvítal např. i BigDecimal
  • chybí jakákoliv podpora pro makra (ani při kopírování nezůstanou zachována)
  • nepodporuje automatickou šířku sloupce (Auto Fit Selection)
  • nelze nastavit typ buňky (viz příklad - vložím vzorec jehož výsledkem je text, ale JExcelApi si při čtení myslí, že to je číslo)
  • tvar vzorců neodpovídá na 100% tvaru z Excelu (chybí uvozovací rovnítko, jako oddělovač parametrů funkcí je použita čárka namísto středníku)
Další věc, která se mi moc nelíbí (a to ani v originálním Excelu) jsou překlady jmen funkcí používaných ve vzorcích. Sice jde jednoduše nastavit, že se použijí původní "americká" jména (WorkbookSettings.setLocale(...)), ale osobně bych to preferoval úplně bez překladů.

A nakonec praktická ukázka:

/**
* Priklad cteni dokumentu pres JExcel
* @throws BiffException
* @throws IOException
* @throws FormulaException
*/
public static void readDemo() throws BiffException, IOException, FormulaException {
    System.out.println("Ctu soubor: " + FILE_NAME);

    // otevreni souboru
    final Workbook wb = Workbook.getWorkbook(new File(FILE_NAME));

    //vypisem vsechny listy
    for (int i=0,m=wb.getNumberOfSheets();i<m;i++) {
        final Sheet sheet = wb.getSheet(i);
        System.out.println("List: " + sheet.getName());

        //vypisem hodnoty v listu
        for (int j=0,n=sheet.getRows();j<n;j++) {
            final Cell[] cells = sheet.getRow(j);
            final StringBuffer tmpStrRow = new StringBuffer();
            for (int k=0; k<cells.length; k++) {

                //spravne bychom tady meli bunku zpracovavat v zavislosti na jejim typu,
                //neb v JavaDocu je metoda getContents oznacena jako "dirty" :)
                tmpStrRow.append(cells[k].getContents());
                //zracovani podle typu bunky muze vypadat nasledovne:
                if (cells[k].getType()==CellType.BOOLEAN_FORMULA
                        || cells[k].getType()==CellType.DATE_FORMULA
                        || cells[k].getType()==CellType.NUMBER_FORMULA
                        || cells[k].getType()==CellType.STRING_FORMULA) {
                    final FormulaCell tmpFormula = (FormulaCell) cells[k];
                    //do zavorky vypiseme vzorech pouzity v teto bunce
                    tmpStrRow.append(" (").append(tmpFormula.getFormula()).append(")");
                }
                tmpStrRow.append("\t");
            }
            System.out.println(tmpStrRow.toString());
        }
    }
    //nakonec zavrem workbook  a uvolnime pamet
    wb.close();
}

/**
* Priklad vytvoreni XLS dokumentu pres JExcel
* @throws IOException see {@link Workbook}
* @throws RowsExceededException see {@link WritableSheet#addCell(jxl.write.WritableCell)}
* @throws WriteException see {@link WritableSheet#addCell(jxl.write.WritableCell)}
*/
public static void writeDemo() throws IOException, RowsExceededException, WriteException {
    System.out.println("Vytvarim soubor: " + FILE_NAME);
    // konfigurace - nechci pouzivat jmena funkci v nemcine :)
    final WorkbookSettings wbs = new WorkbookSettings();
    wbs.setLocale(Locale.US);
    //vytvoreni noveho Workbooku (souboru)
    final WritableWorkbook wb = Workbook.createWorkbook(new File(FILE_NAME),wbs);
    //pridame list
    final WritableSheet sheet = wb.createSheet("Muj super list", 0);
    //nastaveni fontu
    final WritableFont font = new WritableFont(WritableFont.TIMES, 16, WritableFont.BOLD, true);
    final WritableCellFormat cellFormat = new WritableCellFormat(font);

    //pridani stringu
    sheet.addCell(new Label(0,0,"Popisek hodnoty", cellFormat));
    //pridani cisla (bez specialniho formatovani)
    sheet.addCell(new Number(1,0, 1.23456d));
    //pridani vzorce
    sheet.addCell(new Formula(1,1, "CONCATENATE(\"Vysledek vzorce: \",B1+1.90703)"));

    //zapsani do souboru
    wb.write();
    //uvolneni z pameti
    wb.close();
    System.out.println("Soubor ulozen.");
}
výstupem programu bylo na mém německém počítači toto:
Vytvarim soubor: jne5.xls
Soubor ulozen.
Ctu soubor: jne5.xls
List: Muj super list
Popisek hodnoty 1,235 
 4 (VERKETTEN("Vysledek vzorce: ",B1+1.90703))
Celý příklad si můžete stáhnout na adrese http://www.cacek.cz/javlog-attachments/JakNaExcel5.zip

Komentáře

Anonymní píše…
Když spustím stáhnutelný příklad, při vytváření WorkbookSettings mi to vyhodí vyjímku:



Vytvarim soubor: jne5.xls
Exception in thread "main" java.lang.ExceptionInInitializerError
at JExcelApiTest.writeDemo(JExcelApiTest.java:86)
at JExcelApiTest.main(JExcelApiTest.java:116)
Caused by: java.lang.NullPointerException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at common.Logger.initializeLogger(Logger.java:71)
at common.Logger.getLogger(Logger.java:42)
at jxl.WorkbookSettings.[clinit]*(WorkbookSettings.java:42)
... 2 more



(*[clinit] je v ostrych zavorkach, formular mi vsak nedovoli psat tagy)


cestu k souboru mám, si myslím, nastavenou dobře. Každopádně to spadne v době, kdy jí to snad ani nepotřebuje.

Nevíte kde je chyba?
Anonymní píše…
--> tak mi zrejme chybu udelal nekde Eclipse nebo ja. Kdyz jsem vytvoril projekt na jinem pocitaci ve starsim Eclipsu, fungovalo mi to dobre, po presunuti funkcniho projektu mi funguje uz i tady...

Populární příspěvky z tohoto blogu

Three ways to redirect HTTP requests to HTTPs in WildFly and JBoss EAP

WildFly application server (and JBoss EAP) supports several simple ways how to redirect the communication from plain HTTP to TLS protected HTTPs. This article presents 3 ways. Two are on the application level and the last one is on the server level valid for requests to all deployments. 1. Request confidentiality in the deployment descriptor The first way is based on the Servlet specification. You need to specify which URLs should be protected in the web.xml deployment descriptor. It's the same approach as the one used for specifying which URLs require authentication/authorization. Just instead of requesting an assigned role, you request a transport-guarantee . Sample content of the WEB-INF/web.xml <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1

Zipujeme efektivně

Jedna ze základních vlastností Javy je práce se ZIP archívy, ať už jsou to knihovny tříd a spustitelné JARy, webové aplikace (war), nebo třeba JEE bumbrlíčci (ear). Není tedy divu, že i přímo v základním API je implementována práce s těmito archívy. Slouží k tomu třídy v balíku java.util.zip a nejzajímavější z nich jsou ZipOutputStream a ZipInputStream. Příkladem budiž vytvoření zipu: //Vytvorime Zip ZipOutputStream zos = new ZipOutputStream(new FileOutputStream("javlog.zip")); //V Zipu chceme mit jeden textovy soubor zos.putNextEntry(new ZipEntry("priznani.txt")); //naplnime obsah textoveho souboru zos.write("Máme rádi Javu!".getBytes()); //zavrem entry (priznani.txt) zos.closeEntry(); //zavrem stream zos.close(); a jeho rozbalení: ZipInputStream zis = new ZipInputStream(new FileInputStream("javlog.zip")); ZipEntry zipEntry; //budem predpokladat, ze v ZIPu mame jen textove soubory a tak je vypisem do konzole while ((zipEntry = zis.getNextE

jd-cli – Command line Java Decompiler

Kdo by neznal jd-gui Java Decompiler (z free.fr) a jeho sourozence, pluginy pro IDE – Eclipse a IntelliJ. Ale nechyběla vám také někdy možnost rychle decompilovat celý JAR nebo WAR do adresáře, případně zobrazit si decompilovanou třídu jen v konzoli bez nutnosti spouštění GUI? Jestliže ano, pak se zkuste podívat na utilitku jd-cli , která toto všechno umožňuje. Tato aplikace je jednoduchý wrapper nad nativní knihovnou pro jd-gui InelliJ plugin. Kde všude tato java aplikace běží? Windows Linux Mac OSX Kompilace Potřebujete git a Maven. git clone git@github.com:kwart/jd-cmd.git cd jd-cmd mvn clean package Rozbalte jd-cli-[version].zip (.tar.gz) někam, kam odkazuje systémová PATH proměnná ( C:\Windows nebo $HOME/bin ) - distribuce obsahuje i spouštěcí skripty (shell a batch), takže pak už jen vesele voláte jd-cli [aParametry] Příklady použití jd-cli HelloWorld.class Zobrazí dekompilovanou třídu v konzoli jd-cli --skipResources -n -g ALL app.jar Dekompiluje obsah