Как извлечь один файл из удаленного архивного файла?
Учитывая
- URL-адрес архива (например, zip файл)
- Полное имя (включая путь) файла внутри этого архива
Я ищу способ (желательно на Java) создать локальную копию этого файла без первой загрузки всего архива.
Из моего (ограниченного) понимания это должно быть возможно, хотя я понятия не имею, как это сделать. Я использовал TrueZip, поскольку, похоже, он поддерживает большое количество типов архивов, но у меня есть сомнения в его способности работать в таким образом. Кто-нибудь имеет опыт такого рода вещей?
РЕДАКТИРОВАТЬ: возможность также делать это с tarballs и zipped tarballs также важна для меня.
Ответы
Ответ 1
Ну, как минимум, вам нужно загрузить часть архива до и включить сжатые данные файла, который вы хотите извлечь. Это предлагает следующее решение: откройте URLConnection
в архиве, получите его поток ввода, оберните его в ZipInputStream
и повторно вызовите getNextEntry()
и closeEntry()
, чтобы перебирать все записи в файле, пока не достигнете тот, который вы хотите. Затем вы можете прочитать свои данные с помощью ZipInputStream.read(...)
.
Код Java выглядит примерно так:
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);
Это, конечно, непроверено.
Ответ 2
В отличие от других ответов здесь, я хотел бы указать, что записи ZIP сжимаются индивидуально, поэтому (в теории) вам не нужно загружать ничего больше, чем каталог и сама запись. Для этого сервер должен поддерживать HTTP-заголовок Range
.
Стандартный Java API поддерживает только чтение ZIP файлов из локальных файлов и потоков ввода. Насколько я знаю, нет никаких условий для чтения из удаленных файлов с произвольным доступом.
Поскольку вы используете TrueZip, я рекомендую внедрить de.schlichtherle.io.rof.ReadOnlyFile
с помощью Apache HTTP Client и создать с ним de.schlichtherle.util.zip.ZipFile
.
Это не даст никаких преимуществ для сжатых архивов TAR, поскольку весь архив сжимается вместе (помимо использования InputStream и его убийства, когда у вас есть запись).
Ответ 3
С TrueZIP 7.2 в модуле TrueZIP Path появился новый клиентский API. Это реализация NIO.2 FileSystemProvider для JSE 7. Используя этот API, вы можете получить доступ к URI HTTP следующим образом:
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.
...
}
Ответ 4
Я не уверен, есть ли способ вытащить один файл из ZIP без первой загрузки всего. Но если вы являетесь владельцем ZIP файла, вы можете создать сервлет Java, который читает ZIP файл и возвращает запрошенный файл в ответ:
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);
}
}