8i | 9i | 10g | 11g | 12c | 13c | 18c | 19c | 21c | Misc | PL/SQL | SQL | RAC | WebLogic | Linux

Home » Articles » Misc » Here

APEX_ZIP : Manage Zip Files From PL/SQL

The APEX_ZIP package provides an API to manage zip files from PL/SQL. It's installed as part of APEX, but it is available from PL/SQL, so you don't need to be using APEX to use the package.

Related articles.

Setup

Create a directory object and make sure the test user has read/write permissions on it.

conn sys/SysPassword1@//localhost:1521/pdb1 as sysdba

create or replace directory tmp_dir as '/tmp/';
grant read, write on directory tmp_dir to testuser1;

Connect back to the test user and compile the file_to_blob and blob_to_file procedures.

conn testuser1/testuser1@//localhost:1521/pdb1

@https://oracle-base.com/dba/miscellaneous/file_to_blob.sql
@https://oracle-base.com/dba/miscellaneous/blob_to_file.sql

Create a table to hold files in BLOB columns.

# drop table media purge;

create table media (
  id             number generated always as identity,
  content_type   varchar2(100)  not null,
  file_name      varchar2(100)  not null,
  content        blob           not null,
  constraint media_pk primary key (id),
  constraint media_uk unique (file_name)
);

Get a zip file of your choice and put it on the "/tmp" location on the database server. In this example we are using a file called "test_file.zip", which contains PNG files in subdirectories, and includes an empty subdirectory.

We are now ready to start using the the APEX_ZIP package.

GET_FILES Procedure : List File and Directory Names in a Zip File

The GET_FILES function returns the names of the files and directories in the zip file.

The following example loads the zip file into a BLOB, then uses the GET_FILES procedure to retrieve the list of file and directory names into a T_FILES collection. It then loops through the collection displaying the file names.

set serveroutput on
declare
  l_zip    blob;
  l_files  apex_zip.t_files;
begin
  dbms_lob.createtemporary(l_zip, false);

  -- Load the zip file into a BLOB.
  file_to_blob(p_blob     => l_zip,
               p_dir      => 'TMP_DIR',
               p_filename => 'test_file.zip');

  -- Get the list of files.
  l_files := apex_zip.get_files(p_zipped_blob => l_zip);

  -- Loop through the files and list the names.
  for i in 1 .. l_files.count loop
    dbms_output.put_line(i || ' : ' || l_files(i));
  end loop;
  
  dbms_lob.freetemporary(l_zip); 
exception
  when others then
    dbms_lob.freetemporary(l_zip);
    raise;
end;
/
1 : clone/multitenant-clone-2.png
2 : clone/multitenant-create-from-seed-2.png
3 : clone/multitenant-remote-clone-2.png
4 : unplug/multitenant-unplug-plug-2.png


PL/SQL procedure successfully completed.

SQL>

By default the subdirectory directory names are not included in the list. Setting the P_ONLY_FILES parameter to FALSE includes them in the list.

set serveroutput on
declare
  l_zip    blob;
  l_files  apex_zip.t_files;
begin
  dbms_lob.createtemporary(l_zip, false);

  -- Load the zip file into a BLOB.
  file_to_blob(p_blob     => l_zip,
               p_dir      => 'TMP_DIR',
               p_filename => 'test_file.zip');

  -- Get the list of files.
  l_files := apex_zip.get_files(p_zipped_blob => l_zip,
                                p_only_files  => false);

  -- Loop through the files and list the names.
  for i in 1 .. l_files.count loop
    dbms_output.put_line(i || ' : ' || l_files(i));
  end loop;
  
  dbms_lob.freetemporary(l_zip); 
exception
  when others then
    dbms_lob.freetemporary(l_zip);
    raise;
end;
/
1 : clone/
2 : clone/multitenant-clone-2.png
3 : clone/multitenant-create-from-seed-2.png
4 : clone/multitenant-remote-clone-2.png
5 : empty_dir/
6 : unplug/
7 : unplug/multitenant-unplug-plug-2.png


PL/SQL procedure successfully completed.

SQL>

GET_FILE_CONTENT Function : Retrieve Files From a Zip File

The GET_FILE_CONTENT function returns the file from the zip file as a BLOB.

We check the contents of the MEDIA table.

select count(*) from media;

  COUNT(*)
----------
         0

SQL>

This example builds on the first one. Instead of displaying the file name it uses the GET_FILE_CONTENT function to return the file as a BLOB, then inserts it into the MEDIA table.

declare
  l_zip          blob;
  l_files        apex_zip.t_files;
  l_file         blob;
begin
  dbms_lob.createtemporary(l_zip, false);

  -- Load the zip file into a BLOB.
  file_to_blob(p_blob     => l_zip,
               p_dir      => 'TMP_DIR',
               p_filename => 'test_file.zip');

  -- Get the list of files.
  l_files := apex_zip.get_files(p_zipped_blob => l_zip);

  -- Loop through the files and list the names.
  for i in 1 .. l_files.count loop
    l_file := apex_zip.get_file_content(p_zipped_blob => l_zip,
                                        p_file_name   => l_files(i));
    
    insert into media (content_type, file_name, content)
    values ('image/png', l_files(i), l_file);
  end loop;
  commit;
  
  dbms_lob.freetemporary(l_zip); 
exception
  when others then
    dbms_lob.freetemporary(l_zip);
    raise;
end;
/

In this example we know the files in the zip are PNG files, so we're just hard-coding the content type. In a real situation we would have to infer the content type based on the file extension. We are also not stripping the directories from the file names.

Check the contents of the MEDIA table.

column file_name format a40

select id, file_name, length(content) as content_length
from   media;

        ID FILE_NAME                                CONTENT_LENGTH
---------- ---------------------------------------- --------------
         1 clone/multitenant-clone-2.png                      7614
         2 clone/multitenant-create-from-seed-2.png           7222
         3 clone/multitenant-remote-clone-2.png               6192
         4 unplug/multitenant-unplug-plug-2.png               6996

SQL>

ADD_FILE and FINISH Procedures : Create a New Zip File

The ADD_FILE procedure adds a new file to a zip file in a BLOB. It can be called multiple times, and once the last file is added, the FINISH procedure closes off the zip file.

The following example adds all the files from the media table to a new zip file and writes it out to the file system with the name "test_file_2.zip".

declare
  l_zip  blob;
begin
  -- Add the file to a new zip.
  for cur_rec in (select file_name,
                         content
                  from   media)
  loop
    apex_zip.add_file(p_zipped_blob => l_zip,
                      p_file_name   => cur_rec.file_name,
                      p_content     => cur_rec.content);
  end loop;

  -- Close the zip file.
  apex_zip.finish(p_zipped_blob => l_zip);

  -- Write the file to the file system.
  blob_to_file(p_blob     => l_zip,
               p_dir      => 'TMP_DIR',
               p_filename => 'test_file_2.zip');
end;
/

We can check the contents of the "test_file_2.zip" file using the GET_FILES function.

set serveroutput on
declare
  l_zip    blob;
  l_files  apex_zip.t_files;
begin
  dbms_lob.createtemporary(l_zip, false);

  -- Load the zip file into a BLOB.
  file_to_blob(p_blob     => l_zip,
               p_dir      => 'TMP_DIR',
               p_filename => 'test_file_2.zip');

  -- Get the list of files.
  l_files := apex_zip.get_files(p_zipped_blob => l_zip);

  -- Loop through the files and list the names.
  for i in 1 .. l_files.count loop
    dbms_output.put_line(i || ' : ' || l_files(i));
  end loop;
  
  dbms_lob.freetemporary(l_zip); 
exception
  when others then
    dbms_lob.freetemporary(l_zip);
    raise;
end;
/
1 : clone/multitenant-clone-2.png
2 : clone/multitenant-create-from-seed-2.png
3 : clone/multitenant-remote-clone-2.png
4 : unplug/multitenant-unplug-plug-2.png


PL/SQL procedure successfully completed.

SQL>

Comments

Here are some comments about the APEX_ZIP package.

For more information see:

Hope this helps. Regards Tim...

Back to the Top.