logo

Zip Up and Save Space

When you have a database which stores a lot of unzipped attachments, wouldn't it be nice if you could have an agent which periodically runs over them and zips them all? Sure could save a lot of space.

Well, you can and it's not even that difficult. The nice thing is you don't even need Winzip or any other tools to do it, it's already built into the Domino server and client! The magic word is "Java". Java has built in classes for zipping and unzipping files, which we are going to use for this small agent. There is just one small caveat: it only runs on R5.03 servers and above.

First, some things you need to make sure you have so as to get this example up and running:

Create a database, and in that database create a form. Call it whatever you want. On the form, create a rich text field called "Body" (you can call it something else, but then you'll have to modify the agent code below). Also create a view that shows these documents. Now create an agent which should run manually from the actions menu on selected documents.

Copy and paste the code below in to the agent. Don't get scared if it doesn't make a whole lot of sense. There are plenty of comments in the .Java file you can download here - ZipUp.java


// Written by Erwin van Hunen
//
// In this example the agent is run manually from the actions menu on selected documents,
// but of course it would make much more sense to run it as a scheduled or triggered agent
// in the background

import lotus.domino.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;

public class JavaAgent extends AgentBase {

public void NotesMain() {

try {
FileOutputStream fos;
Item item;
RichTextItem rtitem;
String attachmentname;
Vector items;
String archivename;
byte b[] = new byte[512];

Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Database db = agentContext.getCurrentDatabase();

DocumentCollection col = agentContext.getUnprocessedDocuments();

Document doc = col.getFirstDocument();
while (doc != null)
{
archivename = session.getEnvironmentString("Directory",true) + "\\" + doc.getNoteID() + ".zip";

fos = new FileOutputStream(archivename);

ZipOutputStream zout = new ZipOutputStream(fos);

rtitem = (RichTextItem) doc.getFirstItem("Body");

items = doc.getItems();
for (int i=0; i<items.size(); i++) {
item = (Item) items.elementAt(i);
if(item.getType() == Item.ATTACHMENT)
{
if (item.getValueString().length() != 0)
{
attachmentname = item.getValueString();

EmbeddedObject attachment = (EmbeddedObject) doc.getAttachment(attachmentname);

InputStream in = attachment.getInputStream();

ZipEntry e = new ZipEntry(attachment.getName().replace(File.separatorChar,'/'));

zout.putNextEntry(e);
int len=0;

while((len=in.read(b)) != -1)
{
zout.write(b,0,len);
}
zout.closeEntry();
attachment.remove();
}
}
}
zout.close();
fos.close();
doc.replaceItemValue("Body","");
rtitem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, null, archivename, archivename);

doc.save(true);

File zipfile = new File(archivename);
zipfile.delete();

doc = col.getNextDocument(doc);
}

} catch (Exception e) {
e.printStackTrace();
}

}
}

Trying the agent:

Create a document in the database and attach some files in the body field. Save the document, close it, select it in the view and run the agent from the actions menu. When the agent finishes, open the document and you should see a zip file instead of your attachments.

Basically this is what happens when you run the agent:

Domino creates an empty zipfile in the Notes\Data directory which is named after the NoteID of the document. Then it loops through all the attachments on the document and add them to the zipfile. Finally, it deletes the attachments from the document and attaches the zipfile to the document.

I can think of a lot of improvements, like setting a flag which means that the attachments already have been zipped, having a user editable field for the zipfilename, or using the date for the zipfilename, or what about an online zipper? Just provide the user with a form on which he can upload a file, have an agent zip the attachment and present the zipped file?

All in all very straightforward I would say! No need for external libraries, tools, etc. It's all done with built-in functionality of the Domino server and the Notes client. Isn't this the reason why we all love Domino?

Jake's Comments:

Thanks Erwin. Great write up.

You may all have noticed that this isn't really a Domino based solution. When we have a web based application the attachments are rarely in the Body field. This is not to say that it can't be made in to one though, as Erwin mentions. The reason I decided to publish Erwin's article is that it is such good food for thought.

I've placed the code in a file you can download from the top left of the page, to make life easier.

About the Author:

Erwin van Hunen is from The Netherlands and currently works as a Lotus Domino Application Architect for Inter Access B.V.

Feedback

    • avatar
    • Brendon
    • Sat 17 Nov 2001

    Confused

    Hmm...

    Doesn't Notes have a compression function? Why would I do this?

      • avatar
      • Erwin van Hunen
      • Mon 19 Nov 2001

      Re: Confused

      Actually I can come up with at least one reason: say you want to give users the option to upload a set of word documents, which should be made available as a zip file for download.

      This agent can make the zip file without bothering the uploader to create the zip file etc. etc.

      Show the rest of this thread

      • avatar
      • Fabrice P
      • Wed 21 Nov 2001

      Re: Confused

      The compression function of Notes when you attach a file is quite ineficiente.

      Compare when you attach a file with compression active, without compression, to the size of the file if zipped and you'll see from yourself.

      FP (France)

    1. Saves bandwidth...

      When Domino serves up a Domino-compressed attachment, it first decompresses it, then sends it over the wire. But a zip file stays compressed, making for a smaller download.

      The user saves download time, you save money on bandwidth. Everyone's happy!

      Sean

  1. How can I remove the icon

    Hi

    I found the code very usefull but I don't like the deletion of the content of the body field. So I remove that part. But unfortunately, the attachment icon is (although the attachment has been removed) still visible. What can I do to remove the icon?

    Regards Chris

      • avatar
      • Erwin van Hunen
      • Sun 27 Jan 2002

      Re: How can I remove the icon

      That was exactly my problem, which is the only reason I remove the contents of the body field...

      Hide the rest of this thread

        • avatar
        • Christoph Berger
        • Mon 4 Feb 2002

        Re: How can I remove the icon

        Oh, ok.

        If I find a solution to the problem, I'll post it.

        Thanks for the code.

        Regards Chris

          • avatar
          • Christoph Berger
          • Tue 5 Feb 2002

          Re: How can I remove the icon

          Hi Erwin

          I rewrote your code and now it works.

          Regards Chris

          Here's the code:

          //////////////////////////////////////////////////////////////////////////////// ///////// // Agent written by Erwing van Hunen // Extended by Christoph Berger, 04.02.2002 // The following agent loops through all unprocessed (selected) documents, and zips all // attachments unless they have the ending *.zip. // To mark the processed documents, the agent adds in the subject field the text // "<contains zipped files at the end>" //////////////////////////////////////////////////////////////////////////////// /////////

          // used classes import lotus.domino.*; import java.io.*; import java.util.*; import java.util.zip.*; import java.util.Vector; import java.util.Enumeration;

          // standard notes class public class JavaAgent extends AgentBase {

          // main programm public void NotesMain() { try { // declaration of some variables FileOutputStream fos; RichTextItem rtitem; String attachmentname; String archivename; String oldarchive; byte b[] = new byte[512]; // initialize Session session = getSession(); AgentContext agentContext = session.getAgentContext(); Database db = agentContext.getCurrentDatabase(); DocumentCollection col = agentContext.getUnprocessedDocuments(); Document doc = col.getFirstDocument(); // loop through all documents while (doc != null) { // save flag boolean saveFlag = false; // location of the data dir archivename = session.getEnvironmentString("Directory",true) + "\\" + doc.getNoteID() + ".zip"; // create an new file and zip output stream fos = new FileOutputStream(archivename); ZipOutputStream zout = new ZipOutputStream(fos); // get the bodyfield rtitem = (RichTextItem) doc.getFirstItem("Body"); // get all embedded objects and the number Vector v = rtitem.getEmbeddedObjects(); Enumeration e = v.elements(); // loop through all objects while (e.hasMoreElements()) { EmbeddedObject eo = (EmbeddedObject)e.nextElement(); // check if it's an attachment if (eo.getType() == EmbeddedObject.EMBED_ATTACHMENT) { // check the ending of the attachment, if it's a zip file, then it doesn't make sense to zip it again if ( eo.getName().toUpperCase().endsWith( ".ZIP" )); else { InputStream in = eo.getInputStream(); ZipEntry ze = new ZipEntry(eo.getName().replace(File.separatorChar,'/')); zout.putNextEntry(ze); int len=0;

          // read the bytes while((len=in.read(b)) != -1) { zout.write(b,0,len); } // close the entry and remove the attachment zout.closeEntry(); eo.remove(); saveFlag = true; } } } // check if something has changed in the document if (saveFlag) { // close the file- and zip output stream zout.close(); fos.close(); // add some lines to the body item rtitem.addNewLine( 3 );

          // attach the file rtitem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, null, archivename, archivename); // add some text to the subject line doc.replaceItemValue("Subject", doc.getItemValueString("Subject") + " <contains zipped files>"); // save the document doc.save(true, true); saveFlag = false; }

          // close and delete the zip file fos.close(); File zipfile = new File(archivename); zipfile.delete(); // get the next document doc = col.getNextDocument(doc); } // handle the errors } catch (Exception e) { e.printStackTrace(); } } }

            • avatar
            • Christoph Berger
            • Tue 5 Feb 2002

            Recycle

            Hi Erwin

            I have a question. Do you now something about recycling? Is it neccessary to recycle something in the code above?

            Regards Chris

            1. Re: Recycle - yes

              If I understand the workings of Domino Java (I'm kind of new at this too), you should recycle the domino objects in the agent (e.g. database, rtitem, etc) because these don't get garbage collected. Might not matter if the agent only gets run once in a while, but if you run it on a schedule, you could run into memory leak issues, which would eventually force you to restart your server.

              Sean

          1. filename and multiple files

            Great tool - however it would be great if the zipped filename didn't change name. End users do not like this. I've tried it and it works great so far but what about multiple attachments? If you run it on a document with two attachments only one attachment will zipped and the other will be deleted.

    • avatar
    • Adam Gadsby
    • Tue 12 Nov 2002

    Cannot View Files

    Although this works very well to ZIP files, if you click on the attached ZIP file and choose view, you cannot preview the files within the ZIP file. It displays the following error: "Sorry, the program encountered a problem and cannot view the document"

    Normally, you can do this.

    Any ideas?

      • avatar
      • Mr X
      • Fri 31 Jan 2003

      Re: Cannot View Files

      I've test this on a R5 client and an N6 client. The R5 client viewer worked fine. The N6 client gave the error you describe. Didn't find anything in the fixlist for this, but will call support, because this definitely looks like a useful tool.

      Show the rest of this thread

      • avatar
      • Timo
      • Mon 17 Mar 2003

      Re: Cannot View Files

      Hi, did you find a solution? Still using that agent? I would like to share your experiences with that tool.

    • avatar
    • Albina
    • Tue 15 Jul 2003

    Zipping an attachment while sending a mail

    Hi,

    Can this feature be used in Lotus Script also?

    I am trying to send a mail with zipped attachment to save space in recipient's mail box.

    TIA, Albina

  2. can you make this work on domino?

    As Jake said, this isn't really a domino solution since the attachments aren't in the body field. Can you make this work on a domino db where the attachments are uploaded via file upload control?

    What is the difference between this and the other product mentioned - zipmail?

    Thanks!!! :-)

  3. <> What about the other way?

    Has anyone got any examples of taking a zip file and automatically unzipping it?

    Is there any help available on these methods?

    TIA

    Malc.

    1. Re: <> What about the other way?

      hey malc, I am also facing the same problem.have u got any solution for unzipping the zipped attachments.

      Thanks in Advance Ashish Kr.Srivastava

      Show the rest of this thread

  4. Problem with Zipping the content of directory and

    hello i m nikhil. i m trying to zip the contents of directory and the file which are in the sub directory .i have used java.util.zip. Programmes run without any error but when i open the newly zip file it only list the contents of files in the directory but programmes doesnt zip the subdirectory

    thnks nikhil below there is a code import java.util.*; import java.io.*; import java.util.zip.*; class DirTest { public void filePath(String strFilename) { String s[]=new String[0]; ArrayList arr=new ArrayList(); try { File f=new File(strFilename); if(f.isDirectory()) { s=f.list(); } for(int i=0;i<s.length;i++) { File f1=new File(f.getPath()+"/"+ s[i]); if(f1.isDirectory()) { filePath(f1.getPath()); } else { arr.add(f1.getPath()); } } arrListing(arr); } catch(Exception e) { System.out.println(e.getMessage()); } } public void arrListing(ArrayList a1) { try { FileOutputStream fout=new FileOutputStream("C:/myDir/ot.zip"); ZipOutputStream zout=new ZipOutputStream(fout); FileInputStream fin=null; Iterator itr=a1.iterator(); while(itr.hasNext()) { String str=(String) itr.next(); System.out.println(str); zout.setMethod(ZipOutputStream.DEFLATED); zout.setLevel(9); zout.putNextEntry(new ZipEntry(str)); fin=new FileInputStream(str); int c; while((c=fin.read())!=-1) { zout.write(c); } zout.flush(); }

    fin.close(); zout.closeEntry(); zout.close(); } catch(Exception e) { System.out.println(e); } } public static void main(String args[]) throws IOException { DirTest objDir=new DirTest(); objDir.filePath("C:/myDir"); } }

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:



Navigate other articles in the category "Java"

« Previous Article Next Article »
At last, an applet worth using   Multiple Threads in Notes Agents

About This Article

Author: Erwin van Hunen
Category: Java
Keywords: Zip; attachments; file; body;

Attachments

ZipUp.Java (4 Kbytes)

Options

Feedback
Print Friendly

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »