Java: Bzip2 library - java

I need to create Bzip2 archive.
A downloaded bzip2 library from 'Apache ant'.
I use class CBZip2OutputStream:
String s = .....
CBZip2OutputStream os = new CBZip2OutputStream(fos);
os.write(s.getBytes(Charset.forName("UTF-8")));
os.flush();
os.close();
(I didn't find any example how to use it, so I decided to use it in this way)
But it creates a corrupted archive on the disk.

You have to add BZip2 header (two bytes: 'B','Z') before writing the content:
//Write 'BZ' before compressing the stream
fos.write("BZ".getBytes());
//Write to compressed stream as usual
CBZip2OutputStream os = new CBZip2OutputStream(fos);
... the rest ...
Then, for instance, you can extract contents of your bzipped file with cat compressed.bz2 | bunzip2 > uncompressed.txt on a *nix system.

I have not found an example but in the end I understood how to use CBZip2OutputStream so here is one :
public void createBZipFile() throws IOException{
// file to zip
File file = new File("plane.jpg");
// fichier compresse
File fileZiped= new File("plane.bz2");
// Outputstream for fileZiped
FileOutputStream fileOutputStream = new FileOutputStream(fileZiped);
fileOutputStream.write("BZ".getBytes());
// we getting the data in a byte array
byte[] fileData = getArrayByteFromFile(file);
CBZip2OutputStream bzip = null;
try{
bzip = new CBZip2OutputStream(fileOutputStream );
bzip.write(fileData, 0, fileData.length);
bzip.flush() ;
bzip.close();
}catch (IOException ex) {
ex.printStackTrace();
}
fos.close();
}

Related

Using LZ4 Compression in Java for multiple files

I'm trying to compress multiple files into a single archive but with my current code, it only compresses it into a single blob inside the zip. Does anyone know how to segment the files with LZ4?
public void zipFile(File[] fileToZip, String outputFileName, boolean activeZip)
{
try (FileOutputStream fos = new FileOutputStream(new File(outputFileName), true);
LZ4FrameOutputStream lz4fos = new LZ4FrameOutputStream(fos);)
{
for (File a : fileToZip)
{
try (FileInputStream fis = new FileInputStream(a))
{
byte[] buf = new byte[bufferSizeZip];
int length;
while ((length = fis.read(buf)) > 0)
{
lz4fos.write(buf, 0, length);
}
}
}
}
catch (Exception e)
{
LOG.error("Zipping file failed ", e);
}
}
LZ4 algorithm is close with LZMA. In case you can use LZMA then you can create zip archive with LZMA compression.
List<Path> files = Collections.emptyList();
Path zip = Paths.get("lzma.zip");
ZipEntrySettings entrySettings = ZipEntrySettings.builder()
.compression(Compression.LZMA, CompressionLevel.NORMAL)
.lzmaEosMarker(true).build();
ZipSettings settings = ZipSettings.builder().entrySettingsProvider(fileName -> entrySettings).build();
ZipIt.zip(zip)
.settings(settings)
.add(files);
See details in zip4jvm
LZ4 compresses a stream of bytes. You would need to archive your multiple files into a single archive such as a Tar Archive, then feed it into the LZ4 compressor.
I created a Java library that does this for you https://github.com/spoorn/tar-lz4-java.
If you want to implement it yourself, here's a technical doc that includes details on how to LZ4 compress a directory using TarArchive from Apache Commons and lz4-java: https://github.com/spoorn/tar-lz4-java/blob/main/SUMMARY.md#lz4

How to make a copy of a file containing images and text using java

I have some word documents and excel sheets which has some images along with the file text content. I want to create a copy of that file and keep it at a specific location. I tried the following method which is creating file at specified location but the file is corrupted and cannot be read.
InputStream document = Thread.currentThread().getContextClassLoader().getResourceAsStream("upgradeworkbench/Resources/Upgrade_TD_Template.docx");
try {
OutputStream outStream = null;
Stage stage = new Stage();
stage.setTitle("Save");
byte[] buffer= new byte[document.available()];
document.read(buffer);
FileChooser fileChooser = new FileChooser();
fileChooser.setInitialFileName(initialFileName);
if (flag) {
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Microsoft Excel Worksheet", "*.xls"));
} else {
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("Microsoft Word Document", "*.docx"));
}
fileChooser.setTitle("Save File");
File file = fileChooser.showSaveDialog(stage);
if (file != null) {
outStream = new FileOutputStream(file);
outStream.write(buffer);
// IOUtils.copy(document, outStream);
}
} catch (IOException ex) {
System.out.println(ex.getMessage());
}
Can anyone suggest me any different ways to get the proper file.
PS: I am reading the file using InputStream because it is inside the project jar.
PPS: I also tried Files.copy() but it didnt work.
I suggest you never trust on InputStream.available to know the real size of the input, because it just returns the number of bytes ready to be immediately read from the buffer. It might return a small number, but doesn't mean the file is small, but that the buffer is temporarily half-full.
The right algorithm to read an InputStream fully and write it over an OutputStream is this:
int n;
byte[] buffer=new byte[4096];
do
{
n=input.read(buffer);
if (n>0)
{
output.write(buffer, 0, n);
}
}
while (n>=0);
You can use the Files.copy() methods.
Copies all bytes from an input stream to a file. On return, the input stream will be at end of stream.
Use:
Files.copy(document, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
As the class says, the second argument is a Path, not a File.
Generally, since this is 2015, use Path and drop File; if an API still uses File, make it so that it uses it at the last possible moment and use Path all the way.

Automatically download file from URL

I am attempting to download a file automatically. I know the link as I have already parsed it from the RSS XML file. Is there a simple noob friendly way of doing this?
Since my previous edit I have been informed that as long as I keep the file name the same I will be able to do this this is the code I have so far (I should have mentioned previously that this is for a bukkit plugin however the plugin)
public void getFile (String url) {
try{
BufferedInputStream in = new BufferedInputStream(new
URL("http://dev.bukkit.org/media/files/706/595/Kustom-Warn.jar").openStream());
FileOutputStream fileOutputStream = new FileOutputStream(plugin.getDataFolder().getAbsolutePath() + "/KustomWarn.jar");
logger.severe(String.valueOf(plugin.getDataFolder().getAbsolutePath()));
BufferedOutputStream outputStream = new BufferedOutputStream(fileOutputStream,1024);
byte data[] = new byte[1024];
while(in.read(data,0,1024)>=0)
{
outputStream.write(data);
}
outputStream.close();
in.close();
}catch (Exception e){
logger.severe("Error: " + e.getMessage());
}
}
If you mean to copy a file from a site to a local file then you can use java.nio.file
Files.copy(new URL("http://host/site/filename").openStream(), Paths.get(localfile));
Use URL.openStream to open the stream and Java NIO (New I/O) to read efficiently.

Creation gzip archive using Apache Commons Compress

I succeed to create gz archive with expected content, but how can I set the filename inside the archive?
I mean, if archive myfile.gz was created, the file inside it will be named "myfile", but I want to name it like source file, for example, "1.txt"
Current code:
public static void gz() throws FileNotFoundException, IOException {
GZIPOutputStream out = null;
String filePaths[] = {"C:/Temp/1.txt","C:/Temp/2.txt"};
try {
out = new GZIPOutputStream(
new BufferedOutputStream(new FileOutputStream("C:/Temp/myfile.gz")));
RandomAccessFile f = new RandomAccessFile(filePaths[0], "r");
byte[] b = new byte[(int)f.length()];
f.read(b);
out.write(b, 0, b.length);
out.finish();
out.close();
} finally {
if(out != null) out.close();
}
}
GZip compresses a stream. Typically, when people use GZip with multiple files, they also use tar to munch them together.
gzip archive with multiple files inside

Copying / Backingup database to SD card Android

I am using this code and it keeps only getting to the output file line and throws the exception then. Can anyone see what the issue might be with this line?
try{
Log.e("Trying","try");
// Local database
InputStream input = new FileInputStream("/data/data/package/databases/database");
Log.e("Input","in");
// create directory for backup
// Path to the external backup
OutputStream output = new FileOutputStream("/sdcard/android/package/databases/mydatabase.db");
Log.e("Output","out");
// transfer bytes from the Input File to the Output File
byte[] buffer = new byte[1024];
Log.e("Buffer","Buff");
int length;
while ((length = input.read(buffer))>0) {
output.write(buffer, 0, length);
}
Log.e("After While","try");
output.flush();
output.close();
input.close();
} catch (IOException e) {
throw new Error("Copying Failed");
}
I doubt this is the cause of your problem, but the following two lines:
OutputStream output = new FileOutputStream("/sdcard/android/package/databases/mydatabase.db");
InputStream input = new FileInputStream("/data/data/package/databases/database");
should be turned into:
File sdcard = Environment.getExternalStorageDirectory();
File outputFile = new File(sdcard, "android/package/databases/mydatabase.
File data = Environment.getDataDirectory();
File inputFile = new File(data, "data/package/databases/database");
InputStream input = new FileInputStream(inputFile);
OutputStream output = new FileOutputStream(outputFile);
This is because the sdcard and data directories may be in different places on different phones. And often, you need to do /mnt/sdcard/ to actually reference the sd card, but the best way is still to use Files and use Environment as I showed above.
You would of course need to put it all into a try block as you already have, and then within the catch, you will need to put e.printStackTrace(); and then if an error is thrown, you can look at the errors from the logcat to determine where your code fails instead of using a log every couple of lines.
And, in your Manifest you have to have the following permission:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Categories

Resources