2010-06-26 13 views
10

Dada¿Cómo extraer un solo archivo de un archivo de almacenamiento remoto?

  1. URL de un archivo (por ejemplo, un archivo zip)
  2. Nombre completo (incluyendo la ruta) de un archivo dentro de ese archivo

estoy buscando una manera (de preferencia en Java) para crear una copia local de ese archivo, sin descargar todo el archivo primero.

Según mi (limitado) entendimiento, debería ser posible, aunque no tengo ni idea de cómo hacerlo. He estado usando TrueZip, ya que parece admitir una gran variedad de tipos de archivos, pero tengo dudas sobre su capacidad para trabajar de esa manera. ¿Alguien tiene alguna experiencia con ese tipo de cosas?

EDITAR: también es importante para mí hacer tarballs y tarballs con cremallera.

Respuesta

8

Bueno, como mínimo, debe descargar la parte del archivo hasta e incluyendo los datos comprimidos del archivo que desea extraer. Esto sugiere la siguiente solución: abra un URLConnection en el archivo, obtenga su flujo de entrada, envuélvalo en un ZipInputStream, y llame repetidamente al getNextEntry() y closeEntry() para recorrer todas las entradas del archivo hasta llegar al que desea. Luego puede leer sus datos usando ZipInputStream.read(...).

código Java sería algo como esto:

URL url = new URL("http://example.com/path/to/archive"); 
ZipInputStream zin = new ZipInputStream(url.getInputStream()); 
ZipEntry ze = zin.getNextEntry(); 
while (!ze.getName().equals(pathToFile)) { 
    zin.closeEntry(); // not sure whether this is necessary 
    ze = zin.getNextEntry(); 
} 
byte[] bytes = new byte[ze.getSize()]; 
zin.read(bytes); 

Esto es, por supuesto, no probado.

+0

Gracias; esto parece funcionar bien (barra errores menores), aunque desafortunadamente esto no puede manejar nada excepto archivos comprimidos. – Oak

+3

Bueno, sí, ¿por qué crees que se llama 'ZipInputStream'? ;-) Si buscas en Internet, es posible que puedas encontrar un 'TarInputStream' que podrías usar más o menos de la misma manera; de lo contrario, podrías escribir el tuyo. Sería fácil porque los archivos tar no están comprimidos, básicamente es solo un encabezado para cada archivo seguido de los datos del archivo. (Wikipedia tiene una descripción del formato) Para los archivos tar de gzipped, la biblioteca estándar de Java tiene un 'GZIPInputStream' que puede usar junto con la transmisión tar. –

+0

De hecho, Apache tiene una clase [TarInputStream] (http://javadoc.haefelinger.it/org.apache.ant/1.7.1/org/apache/tools/tar/TarInputStream.html) :) – Oak

0

No estoy seguro si hay una manera de extraer un solo archivo de un ZIP sin descargarlo todo primero. Sin embargo, si usted es el que aloja el archivo ZIP, puede crear un servlet de Java que lee el archivo ZIP y devuelve el archivo solicitado en la respuesta:

public class GetFileFromZIPServlet extends HttpServlet{ 
    @Override 
    public void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException{ 
    String pathToFile = request.getParameter("pathToFile"); 

    byte fileBytes[]; 
    //get the bytes of the file from the ZIP 

    //set the appropriate content type, maybe based on the file extension 
    response.setContentType("..."); 

    //write file to the response 
    response.getOutputStream().write(fileBytes); 
    } 
} 
+0

Lamentablemente, no soy el que aloja los archivos ... pero es un buen punto. – Oak

5

Al contrario de las otras respuestas aquí, me gustaría desearía señalar que las entradas ZIP se comprimen individualmente, por lo que (en teoría) no es necesario descargar nada más que el directorio y la entrada en sí. El servidor necesitaría admitir el encabezado HTTP Range para que esto funcione.

La API Java estándar solo admite la lectura de archivos ZIP desde archivos locales y flujos de entrada. Por lo que sé, no hay ninguna disposición para leer archivos remotos de acceso aleatorio.

Dado que está utilizando TrueZip, recomiendo implementar de.schlichtherle.io.rof.ReadOnlyFile usando Apache HTTP Client y creando un de.schlichtherle.util.zip.ZipFile con eso.

Esto no proporcionará ninguna ventaja para los archivos TAR comprimidos ya que todo el archivo se comprime al mismo tiempo (más allá de simplemente utilizar un InputStream y matarlo cuando tenga su entrada).

2

Desde TrueZIP 7.2, hay una nueva API de cliente en el módulo TrueZIP Path. Esta es una implementación de un NIO.2 FileSystemProvider para JSE 7.Con esta API, puede acceder al URI HTTP de la siguiente manera:

Path path = new TPath(new URI("http://acme.com/download/everything.tar.gz/README.TXT")); 
try (InputStream in = Files.newInputStream(path)) { 
    // Read archive entry contents here. 
    ... 
} 
Cuestiones relacionadas