# Perspective download zip file with several files inside

**URL:** <https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035>\
**Category:** Ignition\
**Tags:** database, perspective\
**Created:** [June 14, 2023, 6:00pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035 "2023-06-14T18:00:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alexandre\_Pasquereau](https://avatars.discourse-cdn.com/v4/letter/a/9e8a1a/32.png) [@Alexandre\_Pasquereau](https://forum.inductiveautomation.com/u/Alexandre_Pasquereau)\
**Post date:** [June 14, 2023, 6:00pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/1 "2023-06-14T18:00:54Z")

</div>

Hello there,

I've created an application using perspective. I use it to record data into a database, and then download the recorded data. I'm able to download the data in a csv file, but I can only download one csv file / one table of the database at a time. Now what I'd like to do is to be able to download a zip file with csv files inside that corresponds to the tables of the database.  
My question is: is it possible possible to do that with the command "system.perspective.download" (the one that I use to download the csv file for now) or I need to use a library ?

Thanks!

---

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [June 14, 2023, 6:21pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/2 "2023-06-14T18:21:27Z")

</div>

I happen to do something very similar:

```auto
import io
import zipfile
import jarray

def bytestring_to_jarray(bstring):
	"""
	Convert a Python byte string into a Java jarray

	It's saner to consistently pass byte streams as either the Java-based jarray
	or the Python-based bytearray, but don't mix and match. In particular, Ignition's
	system.file.writeFile doesn't handle the Python types properly. But, Jython's
	file.write doesn't handle the Java types properly.

	I recommend sticking with the Java jarray as much as possible when working in Ignition.

	This function provides a quick way to convert from the Python types to a Java jarray.
	It should've been possible to just do jarray.array(bytearray(), 'b') but Jython seems
	to have a bug.

	If you need to convert back, it's as simple as bytearray(javaTypeData)
	"""
	return jarray.array(((x if x < 128 else (x - 256)) for x in bytearray(bstring)),'b')

def datasets_to_zip(filenames, datasets):
	with io.BytesIO() as tmp_buff:
		with zipfile.ZipFile(tmp_buff, 'w', zipfile.ZIP_DEFLATED) as zfile:
			for file_name, dset in zip(filenames, datasets):
				zfile.writestr(file_name, system.dataset.toCSV(dset))
		tmp_buff.flush()
		byte_result = bytestring_to_jarray(tmp_buff.getvalue())
	return byte_result

```

In my case I was keeping the content in dataset form until the last moment, but you could pass a bunch of CSV strings around as easily as datasets and remove the `toCSV` function.

I hope this helps.

Oh, and you _might_ not need to convert from the Python bytearray to the Java jarray for system.perspective.download, but it's probably safer and I definitely had to before passing the data to system.file.writeFile. When I didn't have that conversion step, the file still wrote okay and looked almost right, but it was corrupted.

---

<div class="post-metadata">

**Author:** ![Alexandre\_Pasquereau](https://avatars.discourse-cdn.com/v4/letter/a/9e8a1a/32.png) [@Alexandre\_Pasquereau](https://forum.inductiveautomation.com/u/Alexandre_Pasquereau)\
**Post date:** [June 14, 2023, 6:31pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/3 "2023-06-14T18:31:38Z")

</div>

Thanks for you answer I'll see if I can solve my problem with it!

---

<div class="post-metadata">

**Author:** ![nellis1](https://avatars.discourse-cdn.com/v4/letter/n/0ea827/32.png) [@nellis1](https://forum.inductiveautomation.com/u/nellis1)\
**Post date:** [August 2, 2023, 4:02pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/4 "2023-08-02T16:02:26Z")

</div>

Just wanted to say a quick thank you to justin.brzozoski, I definitely would have taken me a long time to figure out to convert from the Python bytearray to the Java jarray.

Thank you very much for sharing!

---

<div class="post-metadata">

**Author:** ![justin.brzozoski](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justin.brzozoski/32/13452_2.png) [@justin.brzozoski](https://forum.inductiveautomation.com/u/justin.brzozoski)\
**Post date:** [August 23, 2023, 7:15pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/5 "2023-08-23T19:15:01Z")

</div>

As an exercise to myself, I wanted to see if I could do the same thing with the standard Java library. It produces a jarray as output automatically, and _should_ be more efficient in Jython since it is java-based.

```auto
import java.util.zip.ZipOutputStream as ZipOutputStream
import java.io.ByteArrayOutputStream as ByteArrayOutputStream
import java.util.zip.ZipEntry as ZipEntry

def datasets_to_zip(filenames, datasets):
    byte_stream = ByteArrayOutputStream()
    zip_stream = ZipOutputStream(byte_stream)
    for file_name, dset in zip(filenames, datasets):
        zip_stream.putNextEntry(ZipEntry(file_name))
        zip_stream.write(system.dataset.toCSV(dset))
    zip_stream.close()
    return byte_stream.toByteArray()

```

---

<div class="post-metadata">

**Author:** ![Alexandre\_Pasquereau](https://avatars.discourse-cdn.com/v4/letter/a/9e8a1a/32.png) [@Alexandre\_Pasquereau](https://forum.inductiveautomation.com/u/Alexandre_Pasquereau)\
**Post date:** [August 25, 2023, 11:48am UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/6 "2023-08-25T11:48:34Z")

</div>

Thanks for sharing this!

---

<div class="post-metadata">

**Author:** ![Alexandre\_Pasquereau](https://avatars.discourse-cdn.com/v4/letter/a/9e8a1a/32.png) [@Alexandre\_Pasquereau](https://forum.inductiveautomation.com/u/Alexandre_Pasquereau)\
**Post date:** [February 26, 2024, 3:41pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/7 "2024-02-26T15:41:35Z")

</div>

That is working very well, thank you so much!

---

<div class="post-metadata">

**Author:** ![tmahaf](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tmahaf/32/23492_2.png) [@tmahaf](https://forum.inductiveautomation.com/u/tmahaf)\
**Post date:** [May 16, 2024, 8:44pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/8 "2024-05-16T20:44:54Z")

</div>

Thanks for sharing, this is really great

---

<div class="post-metadata">

**Author:** ![Zachary\_Kacel1](https://avatars.discourse-cdn.com/v4/letter/z/ea666f/32.png) [@Zachary\_Kacel1](https://forum.inductiveautomation.com/u/Zachary_Kacel1)\
**Post date:** [April 23, 2025, 2:04pm UTC](https://forum.inductiveautomation.com/t/perspective-download-zip-file-with-several-files-inside/75035/9 "2025-04-23T14:04:57Z")

</div>

This was really helpful to me. I needed it for downloading multiple images so I slightly changed the script to take a list of image bytes to Zip

```python
 def images_to_zip(filenames, images):
  """
     Creates a zip file containing the provided images.
 
     Args:
         filenames (list of str): List of filenames to be used in the zip file.
         images (list of byte[]): List of byte arrays representing the images.
 
     Returns:
         byte[]: Byte array representing the zip file.
  """
  byte_stream = ByteArrayOutputStream()
  zip_stream = ZipOutputStream(byte_stream)
  
  for file_name, image in zip(filenames, images):
      zip_stream.putNextEntry(ZipEntry(file_name))
      zip_stream.write(image)
      zip_stream.closeEntry()
  
  zip_stream.close()
  return byte_stream.toByteArray()

```
