zipentry tutorial files example java zip

tutorial - Descomprimiendo un archivo ZIP en memoria en Java



zipfile java (4)

EDITAR: Otra sugerencia ...

Mirando ZipFile desde la implementación de Apache Commons, parece que no sería demasiado difícil hacer un enlace efectivo para tu proyecto. Cree una envoltura alrededor de su matriz de bytes que contenga todas las partes de la API RandomAccessFile que se requieren (no creo que haya muchas). Ya has indicado que prefieres la interfaz a ZipFile , ¿por qué no ir con eso?

No sabemos lo suficiente sobre su proyecto para saber si esto genera alguna pregunta legal, e incluso si brindó detalles, dudo que alguien aquí pueda dar un buen asesoramiento legal, pero sospecho que no tomará más que una o dos horas para que esta solución funcione, y sospecho que tendría una confianza razonable en ella.

EDITAR: Esta puede ser una respuesta un poco más productiva ...

Si le preocupa que las entradas no sean contiguas, pero no quiere manejar todo el lado de la compresión, puede considerar una opción donde reescribir los datos de manera efectiva. Cree un nuevo ByteArrayOutputStream y lea el directorio central al final. Para cada entrada en el directorio central, escriba una entrada (encabezado + datos) en el flujo de salida en un formato que crea que ZipInputStream estará contento. Luego, escriba un nuevo directorio central: si desea que su reemplazo sea válido, es posible que deba hacer esto desde cero, pero si está utilizando un código que sabe que realmente no leerá el directorio central, puede proporcionar el original. , ignorando el hecho de que podría no ser válido. Siempre que empiece con la firma correcta, probablemente sea lo suficientemente bueno :)

Una vez que haya hecho eso, convierta ByteArrayOutputStream en un nuevo byte[] , envuélvalo en ByteArrayInputStream y luego páselo a ZipInputStream o ZipInputStream .

Dependiendo de sus propósitos, es posible que ni siquiera tenga que hacer eso; puede simplemente extraer cada archivo a medida que avanza creando un "mini" archivo zip con solo una entrada que está leyendo del directorio a la vez. .

Esto implica comprender el formato del archivo zip, pero no completamente, solo el esqueleto, efectivamente. No es una solución rápida y fácil como usar una API existente por completo, pero no debería llevar mucho tiempo. No garantiza que pueda leer todos los archivos no válidos (¿cómo podría hacerlo?), Pero lo protegerá contra el problema de "datos entre entradas" que le preocupa especialmente. Espero que sea al menos una idea útil ...

no hay manera de decir "aquí hay una matriz de bytes de un archivo zip, úselo"

Sí hay:

byte[] data = ...; ByteArrayInputStream byteStream = new ByteArrayInputStream(data); ZipInputStream zipStream = new ZipInputStream(byteStream);

Eso deja el problema de si ZipInputStream puede manejar todos los archivos zip que le darás, pero no lo escribiría tan rápido.

Por supuesto, hay otras API disponibles. Es posible que desee ver Apache Commons Compress , por ejemplo. A pesar de que ZipFile requiere un archivo, ZipArchiveInputStream no lo hace, así que, una vez más, podría usar un ByteArrayInputStream . EDITAR: Parece que ZipArchiveStream tampoco lee desde el directorio central. Esperaba que usara markSupported para verificar de antemano, pero parece que no ...

EDITAR: En los comentarios sobre la pregunta, le pregunté dónde leería que el archivo zip no tiene que contener datos de entrada. Usted citó wikipedia:

"Las herramientas que leen correctamente los archivos zip deben buscar las firmas de los diversos campos, el directorio central zip. No deben buscar entradas porque solo el directorio especifica dónde se inicia un fragmento de archivo. La exploración puede llevar a falsos positivos, como no lo hace el formato. No prohíba que otros datos se encuentren entre fragmentos, o secuencias sin comprimir que contengan dichas firmas ".

Eso no es lo mismo que los datos de entrada son opcionales. Está diciendo que puede haber datos adicionales en lugares incómodos, no que las entradas pueden faltar por completo. Básicamente, se dice que no se debe asumir que las entradas son contiguas . Con ZipInputStream puedo admitir que ZipInputStream posible que ZipInputStream no esté leyendo el directorio central al final del archivo, pero encontrar el código que hace eso no es lo mismo que encontrar el código que hace frente a los datos de entrada que no existen.

Entonces escribe:

Podría añadir que si el zip es válido o no no es mi preocupación. Trabajar con eso es.

... lo que sugiere que desea código que maneje archivos zip inválidos. Combinado con esto:

Todavía no tengo acceso a los archivos zip que manejaré, así que no sé si podré manejarlos a través de la transmisión.

Eso significa que está solicitando un código que debería manejar archivos zip que no son válidos de una manera que ni siquiera puede predecir. ¿Qué tan inválido tendría que ser para que puedas rechazarlo? Si te doy 1000 bytes aleatorios, sin ningún intento de que sean un archivo zip, ¿qué demonios harías con eso?

Básicamente, debe precisar el problema con mayor precisión antes de que sea factible decir si una biblioteca en particular es una solución válida. Es razonable recopilar un conjunto de archivos zip de varios lugares, que pueden no ser válidos de una manera bien entendida, y decir "Debo ser capaz de admitir todos estos". Más tarde, es posible que tenga que hacer un trabajo si resulta que no fue lo suficientemente bueno. Pero ser capaz de soportar cualquier cosa, por más que esté roto, simplemente no es un requisito válido.

Estoy descargando archivos comprimidos que contienen XML, y me gustaría evitar escribir los archivos zip en el disco antes de manipularlos debido a los requisitos de latencia. Sin embargo, java.util.zip no es suficiente para mí. No hay manera de decir "aquí hay una matriz de bytes de un archivo zip, utilícelo" sin convertirlo en una secuencia, y ZipInputStream no es confiable, ya que busca encabezados de entrada (consulte la discusión EDITAR más abajo por razones por las que no es confiable) .

Todavía no tengo acceso a los archivos zip que ZipInputStream , por lo que no sé si podré manejarlos a través de ZipInputStream , y necesito encontrar una solución que funcione con cualquier archivo ZIP válido , ya que la penalización por un fallo una vez que entre en producción será alta.

Suponiendo que ZipInputStream no funcione, ¿qué puedo hacer para resolver este problema en los casos en que no hay encabezados de entrada? Estoy usando la definición de Wikipedia , que incluye un comentario sobre cómo descomprimir correctamente los archivos zip (citados a continuación), como estándar.

EDITAR

La biblioteca Zip de Apache Commons tiene una buena reseña de algunos de los problemas que tiene Stream (tanto su solución como la de Java). Además, agregaré, de wikipedia y experiencia personal, y el campo de tamaño y crc en los encabezados de entrada puede no llenarse (tengo archivos con -1 en estos campos). Gracias a centic por proporcionar este enlace.

Además, permítanme citar la wikipedia sobre el tema:

Las herramientas que leen correctamente los archivos zip deben buscar las firmas de los diversos campos, el directorio central de zip. No deben buscar entradas porque solo el directorio especifica dónde comienza un fragmento de archivo. El escaneo podría llevar a falsos positivos, ya que el formato no prohíbe que otros datos se encuentren entre fragmentos, o secuencias sin comprimir que contengan dichas firmas.

Tenga en cuenta que ZipInputStream busca entradas, no el directorio central, que es su problema.

Edición final

Si alguien está interesado, esta secuencia de comandos se puede usar para producir un archivo ZIP válido que ZipInputStream no puede leer desde un archivo ZIP existente. Entonces, como una edición final de esta pregunta cerrada, necesitaba una biblioteca que pueda leer archivos como los que produce este script.


Esta pregunta suena similar a ¿Cómo crear un directorio en la memoria? Pseudo sistema de archivos / directorio virtual . Básicamente, mi sugerencia es utilizar una solución más general: un sistema de archivos virtual en memoria (y no me refiero a nivel de SO, como ramfs / tmpfs de Linux).

Un ejemplo es usar las API de Java 7 NIO, que ahora proporcionan un SPI para implementar un sistema de archivos a través de FileSystemProvider . Parece que el ShrinkWrap archivos ShrinkWrap implementa este SPI.

Una opción más accesible sería utilizar el sistema de archivos ram de Apache Commons VFS: solo requiere Java 5. Si necesita ser compatible con Java 5 y 6, esta es probablemente su mejor opción.

Recuerdo por primera vez que leí sobre sistemas de archivos en memoria en Java de este artículo , que además de señalar soluciones como Commons VFS y JBoss Microcontainer , ofrece un buen ejemplo de caso de uso para el IDE de NetBeans.

Si bien un sistema de archivos virtual en la memoria es una buena solución general para evitar el sistema de archivos a nivel del sistema operativo (con los beneficios de rendimiento asociados), probablemente tenga otras desventajas que podrían ser abordadas por soluciones más especializadas. Por ejemplo, no estoy seguro de cómo se comportaría el uso de este sistema de archivos cuando se utilizara simultáneamente desde varios subprocesos. Puede funcionar bien siempre y cuando no acceda a los mismos archivos, o necesite crear sistemas de archivos separados (lo que podría ser prohibitivo en términos de uso de recursos).


Yo usaría la biblioteca de Apache commons-compress, vea http://commons.apache.org/compress/

Tiene soporte para leer archivos Zip a través de secuencias, hay documentación detallada en http://commons.apache.org/compress/zip.html para obtener una documentación detallada. También establece algunas limitaciones que son inherentes al formato Zip.

El código de muestra es el siguiente:

ZipArchiveInputStream zip = new ZipArchiveInputStream(inputStream); try { ZipArchiveEntry entry = zip.getNextZipEntry(); while(entry != null) { assertEquals("README", entry.getName()); ... entry = zip.getNextZipEntry(); } } finally { zip.close(); }


La biblioteca TrueZIP proporciona una implementación zip madura alternativa.

También cuenta con la abstracción del sistema de archivos, incluso para HTTP .

Por ejemplo:

Path path = new TPath(new URI("http://acme.com/download/everything.zip/entry.xml")); try (InputStream in = Files.newInputStream(path)) { // Read archive entry contents here. ... }

Por lo tanto, si está interesado solo en entradas específicas, solo las descargaría, ahorrando tiempo y ancho de banda. Y no tendrías que escribir código de descarga.

Véase también http://truezip.java.net/faq.html#http .