2010-05-19 4 views
1

Je souhaite placer des données compressées dans un référentiel distant.
Pour mettre des données sur ce référentiel, je ne peux utiliser qu'une méthode qui prend le nom de la ressource et son contenu sous la forme d'une chaîne. (comme data.txt + "Bonjour tout le monde").
Le référentiel moque un système de fichiers mais ne l'est pas, donc je ne peux pas utiliser directement le fichier.java: comment obtenir une représentation sous forme de chaîne d'un tableau d'octets compressé?

Je veux être en mesure de faire ce qui suit:

  1. client envoie au serveur un fichier 'donnees.txt
  2. compress serveur' donnees.txt dans un fichier compressé « data.zip »
  3. serveur envoie une représentation de chaîne de data.zip au dépôt
  4. data.zip magasin de dépôt
  5. télécharger le client du référentiel data.zip et son pouvoir l'ouvrir avec son outil zip préféré

Le problème se pose à l'étape 3 lorsque j'essaie d'obtenir une représentation sous forme de chaîne de mon fichier compressé.

Voici une classe d'exemple, utilisant le flux zip * et qui émule le référentiel présentant mon problème.
Le fichier zip créé fonctionne, mais après sa 'sérialisation' il est corrompu.
(l'exemple de classe utilise jakarta commons.io)

Un grand merci pour votre aide.

package zip; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipInputStream; 
import java.util.zip.ZipOutputStream; 

import org.apache.commons.io.FileUtils; 

/** 
* Date: May 19, 2010 - 6:13:07 PM 
* 
* @author Guillaume AME. 
*/ 
public class ZipMe { 
    public static void addOrUpdate(File zipFile, File ... files) throws IOException { 

     File tempFile = File.createTempFile(zipFile.getName(), null); 
     // delete it, otherwise you cannot rename your existing zip to it. 
     tempFile.delete(); 

     boolean renameOk = zipFile.renameTo(tempFile); 
     if (!renameOk) { 
      throw new RuntimeException("could not rename the file " + zipFile.getAbsolutePath() + " to " + tempFile.getAbsolutePath()); 
     } 
     byte[] buf = new byte[1024]; 

     ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile)); 
     ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile)); 

     ZipEntry entry = zin.getNextEntry(); 
     while (entry != null) { 
      String name = entry.getName(); 
      boolean notInFiles = true; 
      for (File f : files) { 
       if (f.getName().equals(name)) { 
        notInFiles = false; 
        break; 
       } 
      } 
      if (notInFiles) { 
       // Add ZIP entry to output stream. 
       out.putNextEntry(new ZipEntry(name)); 
       // Transfer bytes from the ZIP file to the output file 
       int len; 
       while ((len = zin.read(buf)) > 0) { 
        out.write(buf, 0, len); 
       } 
      } 
      entry = zin.getNextEntry(); 
     } 
     // Close the streams 
     zin.close(); 
     // Compress the files 
     if (files != null) { 
      for (File file : files) { 
       InputStream in = new FileInputStream(file); 
       // Add ZIP entry to output stream. 
       out.putNextEntry(new ZipEntry(file.getName())); 
       // Transfer bytes from the file to the ZIP file 
       int len; 
       while ((len = in.read(buf)) > 0) { 
        out.write(buf, 0, len); 
       } 
       // Complete the entry 
       out.closeEntry(); 
       in.close(); 
      } 
      // Complete the ZIP file 
     } 
     tempFile.delete(); 
     out.close(); 

    } 

    public static void main(String[] args) throws IOException { 

     final String zipArchivePath = "c:/temp/archive.zip"; 
     final String tempFilePath = "c:/temp/data.txt"; 
     final String resultZipFile = "c:/temp/resultingArchive.zip"; 

     File zipArchive = new File(zipArchivePath); 
     FileUtils.touch(zipArchive); 

     File tempFile = new File(tempFilePath); 
     FileUtils.writeStringToFile(tempFile, "hello world"); 
     addOrUpdate(zipArchive, tempFile); 

     //archive.zip exists and contains a compressed data.txt that can be read using winrar 

     //now simulate writing of the zip into a in memory cache 
     String archiveText = FileUtils.readFileToString(zipArchive); 
     FileUtils.writeStringToFile(new File(resultZipFile), archiveText); 

     //resultingArchive.zip exists, contains a compressed data.txt, but it can not 
     //be read using winrar: CRC failed in data.txt. The file is corrupt 

    } 

} 

Répondre

1

serveur envoie une représentation de chaîne de data.zip au dépôt

Donc, vous voulez obtenir une chaîne (par exemple textuelle) représentation d'un flux zip (à savoir binaire).

Base64 est le moyen le plus populaire de le faire.

Une implémentation Java populaire est de Apache commons (codec composant)

2

Les fichiers Zip sont binaires. La gestion des chaînes en Java est textuelle et pourrait être mangling ce qu'elle voit comme CRLFs, zéro octets et marqueurs EOF. Quand il s'agit de lire et de réécrire le fichier zip, je suggère que vous essayez avec readFileToByteArray et writeByteArrayToFile comme une expérience. Si cela fonctionne, je soupçonne que la gestion des chaînes est à blâmer.

+0

Je souscris. Lorsque vous transmettez des données binaires, vous devez utiliser Byte, pas Char ou String, qui sont UTF16. –

+0

@Marcus Vous voulez dire UTF-8 (vérifier les accessoires sys). Pour ce travail, vous devrez charger le contenu entier du fichier sous la forme d'un tableau d'octets avant de le convertir en une chaîne. Chaque fois que vous encoder/décoder des octets vers/depuis des chaînes, il existe un risque que les caractères (pouvant traverser plusieurs octets) puissent être codés/décodés de manière incorrecte si un tampon est utilisé. –

+0

@Raymond, merci. Je n'étais probablement pas clair. String et Char sont UTF16 (multi-octets). Les octets sont, évidemment, un seul octet, et c'est ce que vous voulez. –

Questions connexes