Сделать tar-файл по Java

18

Я хочу использовать Java для сжатия папки в файл tar (программным способом). Я думаю, что для этого должен быть открытый источник или библиотека. Однако я не могу найти такой метод.

В качестве альтернативы, могу ли я сделать zip-файл и переименовать его расширенное имя как .tar?

Кто-нибудь может предложить библиотеку для этого? Спасибо!

    
задан 卢声远 Shengyuan Lu 09.08.2011 в 16:33
источник
  • Переименование zip-файла в .tar не делает ничего результативным. Это просто «ложь» о содержании файла. –  Joachim Sauer 09.08.2011 в 16:37
  • Это не дубликат, один запрашивает извлечение tar-файла, который просит его создать. –  Marcelo 09.08.2011 в 16:40
  • Тар не сжимается. Что вам нужно - сжатие или смола? –  user unknown 09.08.2011 в 16:45
  • вы понимаете, что изменение расширения файла фактически не изменяет его содержимое, правильно? –  njzk2 20.01.2014 в 20:20

5 ответов

12

Вы можете использовать jtar - Java Tar library .

Взято со своего сайта:

  

JTar - простая библиотека Java Tar, которая обеспечивает простой способ создания и чтения файлов tar с использованием потоков ввода-вывода. API очень прост в использовании и похож на пакет java.util.zip.

Пример, также со своего сайта:

   // Output file stream
   FileOutputStream dest = new FileOutputStream( "c:/test/test.tar" );

   // Create a TarOutputStream
   TarOutputStream out = new TarOutputStream( new BufferedOutputStream( dest ) );

   // Files to tar
   File[] filesToTar=new File[2];
   filesToTar[0]=new File("c:/test/myfile1.txt");
   filesToTar[1]=new File("c:/test/myfile2.txt");

   for(File f:filesToTar){
      out.putNextEntry(new TarEntry(f, f.getName()));
      BufferedInputStream origin = new BufferedInputStream(new FileInputStream( f ));

      int count;
      byte data[] = new byte[2048];
      while((count = origin.read(data)) != -1) {
         out.write(data, 0, count);
      }

      out.flush();
      origin.close();
   }

   out.close();
    
ответ дан Marcelo 09.08.2011 в 16:37
источник
  • Я использую его, он отлично работает. Благодаря! –  卢声远 Shengyuan Lu 10.08.2011 в 04:27
  • Это отлично работает для файла .txt, но можете ли вы помочь, когда я хочу создать .tar папки. –  Nikita Shah 11.11.2014 в 12:13
  • Мне грозит ошибка времени выполнения: java.lang.NoClassDefFoundError: сбой разрешения: Ljava / nio / file / attribute / PosixFilePermission; пожалуйста, помогите мне, спасибо! –  Beatrice Lin 16.08.2017 в 09:00
  • nikita-shah: см. мое решение. Это может помочь с папками, если у вас есть список файлов. Eventualy итерации файлов в папке с помощью DirectoryStream <Path> stream = Files.newDirectoryStream (dirpath); –  aprodan 07.09.2017 в 19:18
22

Я бы посмотрел Apache Commons Compress .

Ниже приведен пример части вниз этой страницы примеров , в которой показан пример tar.

TarArchiveEntry entry = new TarArchiveEntry(name);
entry.setSize(size);
tarOutput.putArchiveEntry(entry);
tarOutput.write(contentOfEntry);
tarOutput.closeArchiveEntry();
    
ответ дан nicholas.hauschild 09.08.2011 в 16:40
источник
8
Архивные файлы

.tar не сжимаются. Вы должны запустить сжатие файла на нем, как gzip, и превратить его в нечто вроде .tar.gz .

Если вы просто хотите просто архивировать каталог, посмотрите:

ответ дан tskuzzy 09.08.2011 в 16:38
источник
  • Действительно ли это верно, что архивы Тар не сжаты? Я вижу, что сжатие не является прямой целью Tars, но давайте посмотрим на этот сценарий: файловая система работает с блоками размером 4 КБ. Теперь у вас есть произвольные файлы для каждого размера 4KB! = 0, это правда. Поэтому каждый файл тратит <4 Кбайт памяти, потому что он не заполняет свой последний блок. Чем больше файлов, тем больше общих отходов и может стать значительным. Продолжение следует в следующем комментарии ... –  user573215 18.08.2017 в 13:51
  • При объединении всех файлов в один Тар отходы неиспользованного размера блока составляют <4 КБ для всего Тар. Таким образом, было бы что-то вроде неявного сжатия или, по крайней мере, более эффективного использования хранилища. Этот тезис основывается на предположении, что часть отходов каждого финального блока каждого файла будет удалена и не будет скопирована в Tar. Правильно ли предположение и последующие мысли? –  user573215 18.08.2017 в 13:55
  • Wikipedia определяет сжатие как: при обработке сигналов сжатие данных [...] включает в себя информацию о кодировании с использованием меньшего количества бит, чем исходное представление. Таким образом, вы не сжимаете файлы в архиве, вы удаляете дополнение, которое файловая система применяется к ним, чтобы сохранить их на диске. Другими словами, «исходное представление» имеет внутреннюю длину, если файловая система применяет отступы до 4 Кб, она не изменяет длину. На самом деле многие файловые системы даже не делают этого (см. Упаковку хвоста). –  Germano Rizzo 26.01.2018 в 12:45
3

Я разработал следующий код для решения этой проблемы. Этот код проверяет, существует ли какой-либо из файлов, которые будут включены, в файл tar и обновляет эту запись. Позже, если он не существует, добавьте его в конец архива.

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;

public class TarUpdater {

        private static final int buffersize = 8048;

        public static void updateFile(File tarFile, File[] flist) throws IOException {
            // get a temp file
            File tempFile = File.createTempFile(tarFile.getName(), null);
            // delete it, otherwise you cannot rename your existing tar to it.
            if (tempFile.exists()) {
                tempFile.delete();
            }

            if (!tarFile.exists()) {
                tarFile.createNewFile();
            }

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

            TarArchiveInputStream tin = new TarArchiveInputStream(new FileInputStream(tempFile));

            OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(tarFile.toPath()));
            TarArchiveOutputStream tos = new TarArchiveOutputStream(outputStream);
            tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);

            //read  from previous  version of  tar  file
            ArchiveEntry entry = tin.getNextEntry();
            while (entry != null) {//previous  file  have entries
                String name = entry.getName();
                boolean notInFiles = true;
                for (File f : flist) {
                    if (f.getName().equals(name)) {
                        notInFiles = false;
                        break;
                    }
                }
                if (notInFiles) {
                    // Add TAR entry to output stream.
                    if (!entry.isDirectory()) {
                        tos.putArchiveEntry(new TarArchiveEntry(name));
                        // Transfer bytes from the TAR file to the output file
                        int len;
                        while ((len = tin.read(buf)) > 0) {
                            tos.write(buf, 0, len);
                        }
                    }
                }
                entry = tin.getNextEntry();
            }
            // Close the streams
            tin.close();//finished  reading existing entries 
            // Compress new files

            for (int i = 0; i < flist.length; i++) {
                if (flist[i].isDirectory()) {
                    continue;
                }
                InputStream fis = new FileInputStream(flist[i]);
                TarArchiveEntry te = new TarArchiveEntry(flist[i],flist[i].getName());
                //te.setSize(flist[i].length());
                tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
                tos.setBigNumberMode(2);
                tos.putArchiveEntry(te); // Add TAR entry to output stream.

                // Transfer bytes from the file to the TAR file
                int count = 0;
                while ((count = fis.read(buf, 0, buffersize)) != -1) {
                    tos.write(buf, 0, count);
                }
                tos.closeArchiveEntry();
                fis.close();
            }
            // Complete the TAR file
            tos.close();
            tempFile.delete();
        }
    }

Если вы используете Gradle, используйте следующую зависимость:

compile group: 'org.apache.commons', name: 'commons-compress', version: '1.+'

Я также пробовал org.xeustechnologies: jtar: 1.1, но производительность ниже, чем у org.apache.commons: commons-compress: 1.12

Заметки о производительности с использованием различных реализаций:

Zipping 10 раз с использованием Java 1.8 zip:
- java.util.zip.ZipEntry;
- java.util.zip.ZipInputStream;
- java.util.zip.ZipOutputStream;

[2016-07-19 19:13:11]
[2016-07-19 19:13:18] После
7 секунд

Tar-ing 10 раз, используя jtar:
- org.xeustechnologies.jtar.TarEntry;
- org.xeustechnologies.jtar.TarInputStream;
- org.xeustechnologies.jtar.TarOutputStream;

[2016-07-19 19:21:23]
[2016-07-19 19:25:18] После
3m55sec

вызов оболочки для Cygwin / usr / bin / tar - 10 раз
[2016-07-19 19:33:04]
[2016-07-19 19:33:14] После
14 секунд

Tar-ing 100 (сто) раз, используя org.apache.commons.compress:
- org.apache.commons.compress.archivers.ArchiveEntry;
- org.apache.commons.compress.archivers.tar.TarArchiveEntry;
- org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
- org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;

[2016-07-19 23:04:45]
[2016-07-19 23:04:48] После
3 секунды

Таринг 1000 (тысяч) раз, используя org.apache.commons.compress:
[2016-07-19 23:10:28]
[2016-07-19 23:10:48] После
20 секунд

    
ответ дан aprodan 20.07.2016 в 21:28
источник
  • Я не знаю, как установить две или более папки в один .tar? можешь мне помочь ? –  Guo 18.04.2018 в 04:49
  • В основном tar-файл может быть записан последовательно, запись по записи. Чтобы ответить на ваш q, нам нужно знать, что если «tar две папки в одном tar» вы хотите сохранить структуру папок внутри tar или нет. В любом случае вы можете использовать tos.putArchiveEntry (новый TarArchiveEntry (имя)); где имя будет заполнено на основе ваших требований. –  aprodan 19.04.2018 в 22:18
-1

Вы проверили это (Googled "Java tar library"):

Ссылка

Фактически, Поиск Google приводит к большому количеству библиотек.

    
ответ дан Chris Gregg 09.08.2011 в 16:37
источник