mirror of
https://github.com/topjohnwu/jtar.git
synced 2024-11-26 21:00:35 +00:00
Allow TarOutputStream to append to an existing tar file. This is
achieved by positioning the file pointer before the EOF-padding bytes and overwriting them. Additionally, the existing tests were broken and only executable on kamranzafar's machine. The tests should now work on any machine.
This commit is contained in:
parent
1c05a103e4
commit
83b72b4269
2
pom.xml
2
pom.xml
@ -125,6 +125,6 @@
|
||||
</profiles>
|
||||
|
||||
<properties>
|
||||
<skipTests>true</skipTests>
|
||||
<skipTests>false</skipTests>
|
||||
</properties>
|
||||
</project>
|
@ -17,25 +17,50 @@
|
||||
|
||||
package org.kamranzafar.jtar;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* @author Kamran Zafar
|
||||
*
|
||||
*/
|
||||
public class TarOutputStream extends FilterOutputStream {
|
||||
public class TarOutputStream extends OutputStream {
|
||||
private final OutputStream out;
|
||||
private long bytesWritten;
|
||||
private long currentFileSize;
|
||||
private TarEntry currentEntry;
|
||||
|
||||
public TarOutputStream(OutputStream out) {
|
||||
super( out );
|
||||
this.out = out;
|
||||
bytesWritten = 0;
|
||||
currentFileSize = 0;
|
||||
}
|
||||
|
||||
public TarOutputStream(final File fout) throws FileNotFoundException {
|
||||
// TODO: Wrap bufferedoutputstream
|
||||
this.out = new FileOutputStream(fout);
|
||||
bytesWritten = 0;
|
||||
currentFileSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a file for writing.
|
||||
*/
|
||||
public TarOutputStream(final File fout, final boolean append) throws IOException {
|
||||
@SuppressWarnings("resource")
|
||||
RandomAccessFile raf = new RandomAccessFile(fout, "rw");
|
||||
final long fileSize = fout.length();
|
||||
if (append && fileSize > TarConstants.EOF_BLOCK) {
|
||||
raf.seek(fileSize - TarConstants.EOF_BLOCK);
|
||||
}
|
||||
// TODO: Wrap bufferedoutputstream
|
||||
out = new FileOutputStream(raf.getFD());
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the EOF record and closes the stream
|
||||
*
|
||||
@ -45,9 +70,8 @@ public class TarOutputStream extends FilterOutputStream {
|
||||
public void close() throws IOException {
|
||||
closeCurrentEntry();
|
||||
write( new byte[TarConstants.EOF_BLOCK] );
|
||||
super.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte to the stream and updates byte counters
|
||||
*
|
||||
@ -55,7 +79,7 @@ public class TarOutputStream extends FilterOutputStream {
|
||||
*/
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
super.write( b );
|
||||
out.write( b );
|
||||
bytesWritten += 1;
|
||||
|
||||
if (currentEntry != null) {
|
||||
@ -78,7 +102,13 @@ public class TarOutputStream extends FilterOutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
super.write( b, off, len );
|
||||
out.write( b, off, len );
|
||||
|
||||
bytesWritten += len;
|
||||
|
||||
if (currentEntry != null) {
|
||||
currentFileSize += len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
124
src/test/java/org/kamranzafar/jtar/JTarAppendTest.java
Normal file
124
src/test/java/org/kamranzafar/jtar/JTarAppendTest.java
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright 2012 Kamran Zafar
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.kamranzafar.jtar;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class JTarAppendTest {
|
||||
static final int BUFFER = 2048;
|
||||
|
||||
private File dir;
|
||||
private File outDir;
|
||||
private File inDir;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
dir = Files.createTempDirectory("apnd").toFile();
|
||||
dir.mkdirs();
|
||||
outDir = new File(dir, "out");
|
||||
outDir.mkdirs();
|
||||
inDir = new File(dir, "in");
|
||||
inDir.mkdirs();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleOperation() throws IOException {
|
||||
TarOutputStream tar = new TarOutputStream(new FileOutputStream(new File(dir, "tar.tar")));
|
||||
tar.putNextEntry(new TarEntry(TestUtils.writeStringToFile("a", new File(inDir, "afile")), "afile"));
|
||||
copyFileToStream(new File(inDir, "afile"), tar);
|
||||
tar.putNextEntry(new TarEntry(TestUtils.writeStringToFile("b", new File(inDir, "bfile")), "bfile"));
|
||||
copyFileToStream(new File(inDir, "bfile"), tar);
|
||||
tar.putNextEntry(new TarEntry(TestUtils.writeStringToFile("c", new File(inDir, "cfile")), "cfile"));
|
||||
copyFileToStream(new File(inDir, "cfile"), tar);
|
||||
tar.close();
|
||||
|
||||
untar();
|
||||
|
||||
assertInEqualsOut();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAppend() throws IOException {
|
||||
TarOutputStream tar = new TarOutputStream(new FileOutputStream(new File(dir, "tar.tar")));
|
||||
tar.putNextEntry(new TarEntry(TestUtils.writeStringToFile("a", new File(inDir, "afile")), "afile"));
|
||||
copyFileToStream(new File(inDir, "afile"), tar);
|
||||
tar.close();
|
||||
|
||||
tar = new TarOutputStream(new File(dir, "tar.tar"), true);
|
||||
tar.putNextEntry(new TarEntry(TestUtils.writeStringToFile("b", new File(inDir, "bfile")), "bfile"));
|
||||
copyFileToStream(new File(inDir, "bfile"), tar);
|
||||
tar.putNextEntry(new TarEntry(TestUtils.writeStringToFile("c", new File(inDir, "cfile")), "cfile"));
|
||||
copyFileToStream(new File(inDir, "cfile"), tar);
|
||||
tar.close();
|
||||
|
||||
untar();
|
||||
|
||||
assertInEqualsOut();
|
||||
}
|
||||
|
||||
private void copyFileToStream(File file, OutputStream out) throws IOException {
|
||||
final byte[] buffer = new byte[BUFFER];
|
||||
int length = 0;
|
||||
|
||||
try (FileInputStream in = new FileInputStream(file)) {
|
||||
while ((length = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the contents of the input & output dirs are identical.
|
||||
*/
|
||||
private void assertInEqualsOut() throws UnsupportedEncodingException, FileNotFoundException, IOException {
|
||||
assertEquals(inDir.list().length, outDir.list().length);
|
||||
for (File in : inDir.listFiles()) {
|
||||
assertEquals(TestUtils.readFile(in), TestUtils.readFile(new File(outDir, in.getName())));
|
||||
}
|
||||
}
|
||||
|
||||
private void untar() throws FileNotFoundException, IOException {
|
||||
try (TarInputStream in = new TarInputStream(new FileInputStream(new File(dir, "tar.tar")))) {
|
||||
TarEntry entry;
|
||||
|
||||
while ((entry = in.getNextEntry()) != null) {
|
||||
int count;
|
||||
byte data[] = new byte[2048];
|
||||
try (BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(outDir + "/" + entry.getName()))) {
|
||||
while ((count = in.read(data)) != -1) {
|
||||
dest.write(data, 0, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -17,23 +17,34 @@
|
||||
|
||||
package org.kamranzafar.jtar;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class JTarTest {
|
||||
static final int BUFFER = 2048;
|
||||
|
||||
private File dir;
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
dir = Files.createTempDirectory("tartest").toFile();
|
||||
dir.mkdirs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tar the given folder
|
||||
*
|
||||
@ -41,15 +52,24 @@ public class JTarTest {
|
||||
*/
|
||||
@Test
|
||||
public void tar() throws IOException {
|
||||
FileOutputStream dest = new FileOutputStream("/home/kamran/tmp/tartest.tar");
|
||||
FileOutputStream dest = new FileOutputStream(dir.getAbsolutePath() + "/tartest.tar");
|
||||
TarOutputStream out = new TarOutputStream(new BufferedOutputStream(dest));
|
||||
|
||||
tarFolder(null, "/home/kamran/tmp/tartest/", out);
|
||||
File tartest = new File(dir.getAbsolutePath(), "tartest");
|
||||
tartest.mkdirs();
|
||||
|
||||
TestUtils.writeStringToFile("HPeX2kD5kSTc7pzCDX", new File(tartest, "one"));
|
||||
TestUtils.writeStringToFile("gTzyuQjfhrnyX9cTBSy", new File(tartest, "two"));
|
||||
TestUtils.writeStringToFile("KG889vdgjPHQXUEXCqrr", new File(tartest, "three"));
|
||||
TestUtils.writeStringToFile("CNBDGjEJNYfms7rwxfkAJ", new File(tartest, "four"));
|
||||
TestUtils.writeStringToFile("tT6mFKuLRjPmUDjcVTnjBL", new File(tartest, "five"));
|
||||
TestUtils.writeStringToFile("jrPYpzLfWB5vZTRsSKqFvVj", new File(tartest, "six"));
|
||||
|
||||
tarFolder(null, dir.getAbsolutePath() + "/tartest/", out);
|
||||
|
||||
out.close();
|
||||
|
||||
System.out.println("Calculated tar size: " + TarUtils.calculateTarSize(new File("/home/kamran/tmp/tartest")));
|
||||
System.out.println("Actual tar size: " + new File("/home/kamran/tmp/tartest.tar").length());
|
||||
assertEquals(TarUtils.calculateTarSize(new File(dir.getAbsolutePath() + "/tartest")), new File(dir.getAbsolutePath() + "/tartest.tar").length());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,13 +79,17 @@ public class JTarTest {
|
||||
*/
|
||||
@Test
|
||||
public void untarTarFile() throws IOException {
|
||||
String destFolder = "/home/kamran/tmp/untartest";
|
||||
File zf = new File("/home/kamran/tmp/tartest.tar");
|
||||
File destFolder = new File(dir, "untartest");
|
||||
destFolder.mkdirs();
|
||||
|
||||
File zf = new File("src/test/resources/tartest.tar");
|
||||
|
||||
TarInputStream tis = new TarInputStream(new BufferedInputStream(new FileInputStream(zf)));
|
||||
untar(tis, destFolder);
|
||||
untar(tis, destFolder.getAbsolutePath());
|
||||
|
||||
tis.close();
|
||||
|
||||
assertFileContents(destFolder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,15 +99,19 @@ public class JTarTest {
|
||||
*/
|
||||
@Test
|
||||
public void untarTarFileDefaultSkip() throws IOException {
|
||||
String destFolder = "/home/kamran/tmp/untartest/default";
|
||||
File zf = new File("/home/kamran/tmp/tartest.tar");
|
||||
File destFolder = new File(dir, "untartest/skip");
|
||||
destFolder.mkdirs();
|
||||
|
||||
File zf = new File("src/test/resources/tartest.tar");
|
||||
|
||||
TarInputStream tis = new TarInputStream(new BufferedInputStream(new FileInputStream(zf)));
|
||||
tis.setDefaultSkip(true);
|
||||
|
||||
untar(tis, destFolder);
|
||||
untar(tis, destFolder.getAbsolutePath());
|
||||
|
||||
tis.close();
|
||||
|
||||
assertFileContents(destFolder);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,14 +121,16 @@ public class JTarTest {
|
||||
*/
|
||||
@Test
|
||||
public void untarTGzFile() throws IOException {
|
||||
String destFolder = "/home/kamran/tmp/untargztest";
|
||||
File zf = new File("/home/kamran/tmp/tartest.tar.gz");
|
||||
File destFolder = new File(dir, "untargztest");
|
||||
File zf = new File("src/test/resources/tartest.tar.gz");
|
||||
|
||||
TarInputStream tis = new TarInputStream(new BufferedInputStream(new GZIPInputStream(new FileInputStream(zf))));
|
||||
|
||||
untar(tis, destFolder);
|
||||
untar(tis, destFolder.getAbsolutePath());
|
||||
|
||||
tis.close();
|
||||
|
||||
assertFileContents(destFolder);
|
||||
}
|
||||
|
||||
private void untar(TarInputStream tis, String destFolder) throws IOException {
|
||||
@ -169,7 +199,6 @@ public class JTarTest {
|
||||
|
||||
FileInputStream fi = new FileInputStream(fe);
|
||||
origin = new BufferedInputStream(fi);
|
||||
|
||||
TarEntry entry = new TarEntry(fe, parent + files[i]);
|
||||
out.putNextEntry(entry);
|
||||
|
||||
@ -187,7 +216,6 @@ public class JTarTest {
|
||||
|
||||
@Test
|
||||
public void fileEntry() throws IOException {
|
||||
|
||||
String fileName = "file.txt";
|
||||
long fileSize = 14523;
|
||||
long modTime = System.currentTimeMillis() / 1000;
|
||||
@ -209,4 +237,13 @@ public class JTarTest {
|
||||
TarEntry createdEntry = new TarEntry(headerBuf);
|
||||
assertTrue(fileEntry.equals(createdEntry));
|
||||
}
|
||||
|
||||
private void assertFileContents(File destFolder) throws UnsupportedEncodingException, FileNotFoundException, IOException {
|
||||
assertEquals("HPeX2kD5kSTc7pzCDX", TestUtils.readFile(new File(destFolder, "tartest/one")));
|
||||
assertEquals("gTzyuQjfhrnyX9cTBSy", TestUtils.readFile(new File(destFolder, "tartest/two")));
|
||||
assertEquals("KG889vdgjPHQXUEXCqrr", TestUtils.readFile(new File(destFolder, "tartest/three")));
|
||||
assertEquals("CNBDGjEJNYfms7rwxfkAJ", TestUtils.readFile(new File(destFolder, "tartest/four")));
|
||||
assertEquals("tT6mFKuLRjPmUDjcVTnjBL", TestUtils.readFile(new File(destFolder, "tartest/five")));
|
||||
assertEquals("jrPYpzLfWB5vZTRsSKqFvVj", TestUtils.readFile(new File(destFolder, "tartest/six")));
|
||||
}
|
||||
}
|
43
src/test/java/org/kamranzafar/jtar/TestUtils.java
Normal file
43
src/test/java/org/kamranzafar/jtar/TestUtils.java
Normal file
@ -0,0 +1,43 @@
|
||||
package org.kamranzafar.jtar;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
private static final int BUFFER = 2048;
|
||||
|
||||
public static File writeStringToFile(String string, File file) throws UnsupportedEncodingException, FileNotFoundException, IOException {
|
||||
try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
|
||||
writer.write(string);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
public static String readFile(File file) throws UnsupportedEncodingException, FileNotFoundException, IOException {
|
||||
final char[] buffer = new char[BUFFER];
|
||||
final StringBuilder out = new StringBuilder();
|
||||
try (final Reader in = new InputStreamReader(new FileInputStream(file), "UTF-8")) {
|
||||
return readFromStream(buffer, out, in);
|
||||
}
|
||||
}
|
||||
|
||||
public static String readFromStream(final char[] buffer, final StringBuilder out, final Reader in) throws IOException {
|
||||
while (true) {
|
||||
final int read = in.read(buffer, 0, BUFFER);
|
||||
if (read <= 0) {
|
||||
break;
|
||||
}
|
||||
out.append(buffer, 0, read);
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
}
|
BIN
src/test/resources/tartest.tar
Normal file
BIN
src/test/resources/tartest.tar
Normal file
Binary file not shown.
BIN
src/test/resources/tartest.tar.gz
Normal file
BIN
src/test/resources/tartest.tar.gz
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user