We've recently implemented functionality to load ".zip" files from sFTP. However before we've implemented the functionality there was already couple of ".zip" files in there which were treated as ordinary "*.xml" files and downloaded. Now I have a task to restore those downloaded files to zip format.
ZIP files were treated as xml and in doing so they were downloaded in following manner,
CLOB file = downloadFile(channelSFTP.get(fileName), oConn);
:
private static CLOB downloadFile(InputStream is, OracleConnection oConn) throws Exception {
CLOB clob = CLOB.createTemporary(oConn, true, CLOB.DURATION_SESSION);
Writer writer = clob.setCharacterStream(1);
ByteArrayOutputStream result = new ByteArrayOutputStream();
int length = -1;
byte[] buffer = new byte[1024];
while ((length = is.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
result.flush();
writer.write(result.toString("UTF-8"));
writer.flush();
return clob;
}
Then the CLOB is returned from java stored procedure to oracle procedure, and ENCODED in BASE64.
What I've tried to restore files:
public static void decodeZip(String path, String resPath) throws FileNotFoundException, IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new BASE64Decoder().decodeBuffer(new FileInputStream(path), bos);
ZipInputStream zis = new ZipInputStream((InputStream) new ByteArrayInputStream(bos.toByteArray()));
ZipEntry entry;
while((entry = zis.getNextEntry()) != null) {
System.out.println(entry.getName());
}
}
Where "path" is the path of the BASE64 encoded file. However I'm getting the following error:
java.util.zip.ZipException: invalid stored block lengths
on "zis.getNextEntry()". I think it should be possible to achieve this, but i can't seem to figure out, what step I'am missing.
Related
I'm trying to convert an existing CSV file to a gzip file.
I verified the CSV looks good. Once I run this code, I get a "failed to expand" error and tried an online decompression tool that also failed, so it seems the output zip is corrupt.
public void compressGzip(String input, String dest) throws IOException {
Path pathSource = Paths.get(input);
Path destSource = Paths.get(dest);
try (GZIPOutputStream gos = new GZIPOutputStream(
new FileOutputStream(destSource.toFile()));
FileInputStream fis = new FileInputStream(pathSource.toFile())) {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
gos.write(buffer, 0, len);
}
}
}
Anything I could be missing here?
Have a Word DOCX file stored in a table (zip file). With Java stored procedure, I like to replace some string inside "word/document.xml" file and store all files into new archive. If I run the code on Oracle database I get corrupted zip file. File size of ouptut file is smaller than input file...
If I run the same app on client (Netbeans IDE) then all works fine. I can't find the where is the problem!?
public static void zamenjajVsebino(oracle.sql.BLOB srcBlob1, oracle.sql.BLOB[] dstBlob) throws Exception {
InputStream zipBuffer = srcBlob1.getBinaryStream();
OutputStream outBuffer = dstBlob[0].getBinaryOutputStream();
ZipInputStream zipIn = new ZipInputStream(zipBuffer);
ZipOutputStream zipOut = new ZipOutputStream(outBuffer);
ZipEntry inEntry;
while ((inEntry = zipIn.getNextEntry()) != null) {
ZipEntry outEntry = new ZipEntry(inEntry.getName());
zipOut.putNextEntry(outEntry);
if (inEntry.getName().equals("content.xml") | inEntry.getName().equals("word/document.xml")) {
String contentIn = new String(getStringByte(zipIn), "UTF-8");
contentIn = contentIn.replaceAll("%TEXT%", "BLA BLA");
zipOut.write(contentIn.getBytes(), 0, contentIn.getBytes().length);
} else {
copy(zipIn, zipOut);
}
zipOut.closeEntry();
}
zipIn.close();
zipOut.flush();
zipOut.finish();
}
public static void copy(InputStream in, OutputStream out) throws IOException {
int n;
byte[] buffer = new byte[1024];
while ((n = in.read(buffer)) > -1) {
out.write(buffer, 0, n); // Don't allow any extra bytes to creep in, final write
}
out.flush();
}
If I open the source DOCX file is like this:
The output file is like this:
Here is my plsql source code:
-- select source docx file from blob...
select vdb.vsebina
into SrcBlobLocator
from dok_vsebina_dokumenta_blob vdb
where id=p_vdb_id;
-- prepare output blob
p_vdb_id_out:=dok_lob.f_pripravi_blob;
update dok_vsebina_dokumenta_blob set
naziv_datoteke='test.docx',
vsebina = empty_blob()
where id=p_vdb_id_out;
--select output blob for update...
select vdb.vsebina
into DstBlobLocator
from dok_vsebina_dokumenta_blob vdb
where id=p_vdb_id_out for update;
-- call java stored procedure with source and dest blob...
ZamenjajVsebino(SrcBlobLocator, DstBlobLocator);
I am trying to transfer a SQLite database into an app by downloading it and then unzipping it to the correct location. I was successful in transferring the DB when it was unzipped. The error I get is that it cannot find any of the tables I query. I have also been successful in unzipping and reading normal text files.
The DB has Hebrew and English, but that has not caused problems before. The bilingual DB was copied successfully when it was not zipped and bilingual texts have been successfully unzipped and read. Still, it is a possibility that there is an encoding problem going on. That seems weird to me, because as you can see below in the code, I'm just copying the bytes directly.
-EDIT-
Let's say the prezipped db is called test1.db. I zipped it, put it in the app, unzipped it and called that test2.db. when I ran a diff command on these two, there were no differences. So there must be a technical issue with the way android is reading the file / or maybe encoding issue on android that doesn't exist on pc?
I hate to do a code dump, but i will post both my copyDatabase() function (which works). That is what I used previously running it on an unzipped DB file. I put it here as comparison. Now I'm trying to use unzipDatabase() function (which doesn't work), and use it on a zipped DB file. The latter function was copied from How to unzip files programmatically in Android?
private void copyDatabase() throws IOException{
String DB_NAME = "test.db";
String DB_PATH = "/data/data/org.myapp.myappname/databases/";
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
private boolean unzipDatabase(String path)
{
String DB_NAME = "test.zip";
InputStream is;
ZipInputStream zis;
try
{
String filename;
is = myContext.getAssets().open(DB_NAME);
zis = new ZipInputStream(is);
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null)
{
// write to a file
filename = ze.getName();
// Need to create directories if not exists, or
// it will generate an Exception...
if (ze.isDirectory()) {
Log.d("yo",path + filename);
File fmd = new File(path + filename);
fmd.mkdirs();
continue;
}
OutputStream fout = new FileOutputStream(path + filename);
// reading and writing zip
while ((count = zis.read(buffer)) != -1)
{
fout.write(buffer, 0, count);
}
fout.flush();
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
So still don't know why, but the problem is solved if I first delete the old copy of the database (located at DB_PATH + DB_NAME) and then unzip the new one there. I didn't need to do this when copying it directly.
so yay, it was a file overwriting issue...If someone knows why, feel free to comment
I need to package a few files (total upto 4 GB in size) which will be available online. An android app needs to download this 'on the fly' without saving the archive on to the device. So basically the device won't save the archive and then unpack, as it would require double the space. Which package format should I choose that will support it (eg. zip, tar.gz etc.)?
Use .zip! You can use ZipInputStream and ZipOutputStream to read and write from .zip files on the fly. No need to extract the files from the archive.
Link to documentation
And here is a quick example:
InputStream is =...
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(is));
try {
// ZipEntry contains data about files and folders in the archive.
ZipEntry ze;
// This loops through the whole content of the archive
while ((ze = zis.getNextEntry()) != null) {
// Here we read the whole data of one ZipEntry
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
baos.write(buffer, 0, count);
}
// The ZipEntry contains data about the file, like its filename
String filename = ze.getName();
// And that's the file itself as byte array
byte[] bytes = baos.toByteArray();
// Do something with the file
}
} finally {
zis.close();
}
I am trying to copy a file (Base.jar) to the same directory as the running jar file
I keep getting a corrupted jar file, that still holds the correct class structure when opened with winrar. What am I doing wrong? (I have also tried without the ZipInputStream, but that was no help) the byte[] is 20480 because that is size of it on the disk.
my code:
private static void getBaseFile() throws IOException
{
InputStream input = Resource.class.getResourceAsStream("Base.jar");
ZipInputStream zis = new ZipInputStream(input);
byte[] b = new byte[20480];
try {
zis.read(b);
} catch (IOException e) {
}
File dest = new File("Base.jar");
FileOutputStream fos = new FileOutputStream(dest);
fos.write(b);
fos.close();
input.close();
}
InputStream input = Resource.class.getResourceAsStream("Base.jar");
File fileOut = new File("your lib path");
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
and handle exceptions
No need to use ZipInputStream, unless you want to unzip the contents into memory and read.
Just use BufferedInputStream(InputStream) or BufferedReader(InputStreamReader(InputStream)).
did some more googling found this: (Convert InputStream to byte array in Java) worked for me
InputStream is = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
(it looks very simular to the src for IOUtils.copy())
ZipInputStream is for reading files in the ZIP file format by entry. You need to copy the whole file (resource) that is you need to simply copy all bytes from InputStream no matter what format is. The best way to do it in Java 7 is this:
Files.copy(inputStream, targetPath, optionalCopyOptions);
see API for details