[Java] Zip- + Object(stream) openen via URL

Pagina: 1
Acties:

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
Ik heb wel al wat rondgekeken op Internet en voorbeelden van hoe ik m.b.v. een ZipFile klasse een Zip moet uitpakken. Dat is geen probleem op zich. Maar mijn probleem strekt zich wat verder dan dat, ik wil namelijk een ZIP-bestand openen vanuit een URL en dat ZIP-bestand bevat een gedumpt Hashmap-object.

Ik heb dus een HashMap gedumpt naar een bestand, deze heb ik daarna als ZIP ingepakt en op de server gezet. Vervolgens moet mijn Java-clientprogramma het liefst deze direct kunnen openen via een URLConnection, direct uitkunnen pakken en direct de opgeslagen HashMap uit die ZIP in het geheugen stoppen. Dus eigenlijk wil ik niet dat die ZIP eerst moet worden gedownload als bestand oid, maar als stream.

Ik zie eigenlijk door de bomen het bos niet, want volgens mij moet ik een combinatie verzinnen van ZipInputStream, ObjectInputStream en een URLConnection.

Java:
1
2
3
4
5
6
7
ObjectInputStream os;
ZipInputStream zis;
URL url = new URL("http://server.com/bestand.zip");
URLConnection conn = url.openConnection();

zis = new ZipInputStream(url.openStream());
os = new ObjectInputStream(zis);


Maar hoe haal ik nu exact een bestand uit die ZIP-stream op (bijvoorbeeld "hashmap.obj")? Moet ik met ZipEntries werken? Want als dat zo is, dan moet je weer een extra stream openen volgens mij om die entries uit een ZIP-bestand te pakken, ik kom er niet echt uit. Gaarne hulp en of wijselijk inzichtelijke hulp gewenst :)

[ Voor 12% gewijzigd door Tjeerd op 21-12-2006 10:59 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 09:47
Typisch gevalletje van RTFM. :)

Kijk hier eens naar:
http://java.sun.com/j2se/...tream.html#getNextEntry()
http://java.sun.com/j2se/...ead(byte[],%20int,%20int)

Flikker die objectinput stream er maar weer even vanaf. Haal de next entry op net zolang totdat je de juiste file hebt. Vervolgens read aanroepen met een buffer wat groot genoeg is, benodigde size kun je uit je actuele zip entry halen. De resulterende byte array in een ByteArrayInputStream stoppen en deze door de ObjectInputStream halen.

[ Voor 1% gewijzigd door The - DDD op 21-12-2006 11:46 . Reden: Tnx BalusC ]


  • BalusC
  • Registratie: Oktober 2000
  • Niet online

BalusC

Carpe diem

offtopic:
Je kunt url's met blokhaken erin het beste tussen [url] en [/url] plaatsen ;)
Zo dus: http://java.sun.com/j2se/...ead(byte[],%20int,%20int)

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
Dank voor de reacties, ik heb trouwens nu het volgende en dat is wat betreft het ophalen van de ZIP vanaf een URL en de bestanden die daarin zitten voldoende. Het geeft een Vector van gedecomprimeerde bestanden terug:

Java:
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
public Vector unZipURL(String theURL) {
         ZipInputStream zis = null;         
         FileInputStream in = null;      
         ZipEntry ze = null; 
         Vector zipfiles = new Vector(); 
         
         try {
             URL url = new URL(theURL);
             URLConnection conn = url.openConnection();
             conn.setDoInput(true);
             conn.setDoOutput(false);
             conn.setUseCaches(false);
             conn.setDefaultUseCaches(false);
             conn.connect();
             
             zis = new ZipInputStream(conn.getInputStream());
             
             ze = zis.getNextEntry();
             
             while (ze != null) { 
                long decompressedSize = ze.getSize(); 
                byte[] uncompressedBuf = new byte[(int)decompressedSize]; 
                zis.read(uncompressedBuf); 
                zipfiles.add(uncompressedBuf); 
                ze = zis.getNextEntry(); 
             } 
             
         } catch (Exception ex) { ex.printStackTrace(); }
         
         return zipfiles;
     }   


Code om de buffer - byte[] arrays die in de zipfiles-Vector zitten - om te zetten naar een Object:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
public Object Buffer2Object(byte[] buffer) {
         ByteArrayInputStream bis = null;
         ObjectInputStream os = null;
         Object o = null;
         
         try {
             bis = new ByteArrayInputStream(buffer);
             os = new ObjectInputStream(bis);
             o = os.readObject();
         } catch (Exception ex) { ex.printStackTrace(); };
    
         return o;
     }

Altijd handig voor andere mensen die ook zoiets willen doen. Geloof dat dit vrij goed werkt.

[ Voor 20% gewijzigd door Tjeerd op 21-12-2006 13:28 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 09:47
Ja dat is zo'n beetje wat ik al zei. :D

Stukje code kan iets netter wat je post. Ik zou eerder in deze richting zitten. Ik zou zelfs overwegen om het aanmaken van de inputstream buiten deze methode te laten. Want als je remote files wilt unzippen, dan zul je het vast ook met lokale files moeten doen. Maar dan moet je weer heel netjes met je in en output stream om blijven gaan.

Java:
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
public ArrayList unZipURL(String theURL) {
    ZipInputStream zis = null;         
    ArrayList zipfiles = new ArrayList(); 
    
    try {
        URL url = new URL(theURL);
        URLConnection conn = url.openConnection();
        conn.setDoOutput(false);
        conn.setUseCaches(false);
        conn.setDefaultUseCaches(false);
        conn.connect();
        
        zis = new ZipInputStream(conn.getInputStream());
        
        for (ZepEntry ze = zis.getNextEntry(); ze != null; ze.getNextEntry()){
            long decompressedSize = ze.getSize(); 
            byte[] uncompressedBuf = new byte[(int)decompressedSize]; 
            zis.read(uncompressedBuf); 
            zipfiles.add(uncompressedBuf); 
        }
    } catch (Exception ex) {
        //Ranzig, hier specifiekere afhandeling doen.
        ex.printStackTrace();
    } finally {
        try {
            if (zis != null) {
                zis.close();
            }
        } catch (Exception ex) {
            //Ranzig, hier specifiekere afhandeling doen.
            ex.printStackTrace();
        }
    }
    
    return zipfiles;
}


Ik zou er eerder zoiets van maken. Kan og wat meer commentaar gebruiken en iets betere foutafhandeling :X

  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
Ondertussen vakantie gehad en nu ben ik weer bezig met die Buffer2Object-methode, om één of andere reden gaat het daar nu fout en krijg ik daar een java.io.StreamCorruptedException.

Het inlezen van een ZIP via een URL lijkt goed te gaan, ik krijg een byte[] array terug die 14 MB is, dat is precies de grootte van het bestand wat ingepakt als ZIP staat op de server. Dat bestand is goed qua inhoud, dat is een geserializde HashMap.

Het gaat fout bij het openen van een ByteArrayInputStream, dan krijg ik een StreamCorruptedException:

Java:
1
2
3
4
5
6
7
8
9
10
ByteArrayInputStream bis = null;
ObjectInputStream os = null;
Object o = null;

try {
     System.err.println(buffer.length); // geeft ongeveer 14 MB aan
     bis = new ByteArrayInputStream(buffer); //hier krijg ik de StreamCorruptedException            
     os = new ObjectInputStream(bis);
     o = os.readObject();
} catch (Exception ex) { ex.printStackTrace(); };


Ik vat maar niet waarom het daar fout gaat, is die byte[]-buffer te groot oid? Op GoT kon ik niets vinden en op de Java-fora ook niet, vandaar hier mijn vraag.

[ Voor 6% gewijzigd door Tjeerd op 08-01-2007 14:59 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • ari3
  • Registratie: Augustus 2002
  • Niet online
Nestor schreef op maandag 08 januari 2007 @ 14:37:
Ondertussen vakantie gehad en nu ben ik weer bezig met die Buffer2Object-methode, om één of andere reden gaat het daar nu fout en krijg ik daar een java.io.StreamCorruptedException.

Ik vat maar niet waarom het daar fout gaat, is die byte[]-buffer te groot oid? Op GoT kon ik niets vinden en op de Java-fora ook niet, vandaar hier mijn vraag.
De byte[] is een representatie van je ZIP-file en dus geen geserialiseerde java object. Uit het ZIP-bestand moet je een ZipEntry halen die je dan vervolgens kunt deserialiseren.

"Kill one man, and you are a murderer. Kill millions of men, and you are a conqueror. Kill them all, and you are a god." -- Jean Rostand


  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
Ik vraag me af of dat het kan zijn, ik denk namelijk van niet:

- originele geserializeerde bestand = 14704617 bytes (=HashMap van objecten)
- inpakken als ZIP, op de server zetten
- ZIP uitpakken met methode die in dit topic staat (unZipURL)
- buffer[] vullen adhv methode die in dit topic staat (ophalen uit de vector die unZipURL geeft)
- buffer[] is wederom netjes 14704617 bytes groot

Het *lijkt* erop dat de buffer dus geen overhead of iets dergelijks van het ZIP-bestand heeft meegekregen. Mocht het trouwens wel zo zijn, waarom krijg ik dan een vreemde StreamCorruptedException? Het lijkt mij dat een ByteArrayInputStream verder niet geinteresseerd is in het soort byte[]-array hij aangeboden krijgt?

[ Voor 30% gewijzigd door Tjeerd op 08-01-2007 15:57 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • ari3
  • Registratie: Augustus 2002
  • Niet online
Gebruik je trouwens exact dezelfde JVM (fabrikant en versie) om te serialiseren en deserialiseren?

De Javadoc zegt dat een StreamCorruptedException optreed wanneer de volgende conditie optreedt: "Control information in the stream is inconsistent." Kun je de byte[] en de originele byte[] eens met elkaar vergelijken?

"Kill one man, and you are a murderer. Kill millions of men, and you are a conqueror. Kill them all, and you are a god." -- Jean Rostand


  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
ari3 schreef op maandag 08 januari 2007 @ 15:56:
Gebruik je trouwens exact dezelfde JVM (fabrikant en versie) om te serialiseren en deserialiseren?

De Javadoc zegt dat een StreamCorruptedException optreed wanneer de volgende conditie optreedt: "Control information in the stream is inconsistent." Kun je de byte[] en de originele byte[] eens met elkaar vergelijken?
Bedankt voor dit antwoord, ik ga dat eens proberen nu, trouwens:
Java Runtime: Using JRE version 1.5.0_02 Java HotSpot(TM) Client VM

Java compiler (javac --version):
java version "1.5.0_01"
Minimaal verschil, maar het is er wel. Zou dat het kunnen zijn, dat zou weer een mooi verhaal zijn dan :(

[ Voor 45% gewijzigd door Tjeerd op 08-01-2007 16:05 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • ari3
  • Registratie: Augustus 2002
  • Niet online
ari3 schreef op maandag 08 januari 2007 @ 15:56:
Gebruik je trouwens exact dezelfde JVM (fabrikant en versie) om te serialiseren en deserialiseren?
In aanvulling op hetgeen hierboven staat moet je ook de compiler in overweging nemen. De ingebouwde compiler van Eclipse gegenereert iets anders dan de Sun compiler. Dit merk je vooral bij serialisatie en deserialisatie.

"Kill one man, and you are a murderer. Kill millions of men, and you are a conqueror. Kill them all, and you are a god." -- Jean Rostand


  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
(Helaas) is dit een wat ouder project wat nog in Netbeans 4.0 geschreven is (huidige projecten doe ik in Eclipse). Maar wat ik zo gauw zie staat Netbeans ingesteld op "C:\Program Files\Java\jdk1.5.0_01", hij compileert dus met een fractie oudere compiler en draait hem op "jre1.5.0_02".

Ik heb de byte[] buffer als bestand weggeschreven en deze vergeleken met het originele bestand (de groottes zijn wel hetzelfde) en het Linux diff-commando geeft aan dat ze verschillen. Ik ga nu uitzoeken wat het verschil dan is.

[ Voor 29% gewijzigd door Tjeerd op 08-01-2007 16:33 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.


  • Tjeerd
  • Registratie: Oktober 1999
  • Laatst online: 15:40

Tjeerd

Be Original, Be Yourself.

Topicstarter
Ik heb zojuist even gekeken naar het verschil tussen het gedownloade 'serialized' bestand (uit de ZIP op de server) en de lokaal opgeslagen versie. Wat blijkt, de eerste ruim 500 bytes zijn hetzelfde. Er staat een HashMap-header in en een object-header wat opgeslagen is in de HashMap. Maar dat is dan de enige overeenkomst tussen beide bestanden, vanaf die 500 bytes is het geserializde bestand (wat uit de ZIP van de URL komt) 14 MB aan '00' waarden: dus helemaal leeg.

Blijkbaar gaat er iets fout in de unZIPUrl-methode die ik in dit topic heb staan :?

UPDATE:

Ik heb een kleine aanpassing gedaan met dank aan een goede vriend, deze aangepaste versie haalt alles *wel* goed binnen, het lijkt te maken te hebben met de buffer:

Java:
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
public Vector unZipURL(String theURL) {
         ZipInputStream zis = null;         
         FileInputStream in = null;
         ByteArrayOutputStream baos = null;
         Enumeration entries = null;         
         byte[] buffer = new byte[4096];
         
         int read=0;
         ZipEntry ze = null; 
         baos = new ByteArrayOutputStream();
         Vector zipfiles = new Vector(); 
         
         try {            
             URL url = new URL(theURL);
             URLConnection conn = url.openConnection();
             conn.setDoInput(true);
             conn.setDoOutput(false);
             conn.setUseCaches(false);
             conn.setDefaultUseCaches(false);
             conn.connect();
             
             zis = new ZipInputStream(conn.getInputStream());
            
             ze = zis.getNextEntry();
             while (ze!=null) {
                long decompressedSize = ze.getSize(); 
                byte[] uncompressedBuf = new byte[(int)decompressedSize]; 
                
                while((read = zis.read(buffer)) > 0){
                    baos.write(buffer, 0, read); 
                }
                
                zipfiles.add(baos.toByteArray());
                
                //zis.read(uncompressedBuf); 
                zipfiles.add(uncompressedBuf);
                ze=zis.getNextEntry();
            } 
             
         } catch (Exception ex) { ex.printStackTrace(); }
         
         return zipfiles;
     }

[ Voor 60% gewijzigd door Tjeerd op 09-01-2007 10:24 ]

www.tjeerd.net - To repeat what others have said, requires education, to challenge it, requires brains.

Pagina: 1