Help with ZIPReader and PackedByteArray

Godot Version

Godot 4.4.1

Question

Hi,
I’m messing around with ZIPPacker and ZIPReader classes, and they use PackedByteArray for their file data. I don’t understand how to convert the data to and from PackedByteArray form.

The example in the documentation looks very easy:

writer.write_file("Hello World".to_utf8_buffer())

So it makes a string and converts it to utf8. Cool, I can convert my vector data data to string (JSON.stringify) and then to utf8. It works but feels stupid.

Then when loading it:

reader.read_file("somefile").get_string_from_utf8()

I can get the bytes and convert that to string and parse vector data from that… Soo many conversions.

What’s the correct way? My data is just an array of vectors.

Did this help you ?

Zip test
extends Node2D

var ZipFileName = "user://archive.zip"

# Called when the node enters the scene tree for the first time.
func _ready():
	var vectorlist = [Vector2(1,2), Vector2(3,4), Vector2(5,6), Vector2(8,9)]
	
	var packed = PackedByteArray(PackedVector2Array(vectorlist).to_byte_array());
	
	write_zip_file("vectors.data", packed)
	var unpacked = read_zip_file("vectors.data")
	
	var newvectorlist = bytes_to_packed_vector2_array(unpacked)
		
	prints("Expected :", vectorlist)
	prints("Get      :", newvectorlist)

func bytes_to_packed_vector4_array(bytes: PackedByteArray) -> PackedVector4Array:
	if bytes.size() % 16 != 0:
		return []
	var result: PackedVector4Array = []
	var count: int = bytes.size() / 16
	result.resize(count)
	for i in count:
		result[i] = Vector4(bytes.decode_float(i * 16), bytes.decode_float(i * 16 + 4), bytes.decode_float(i * 16 + 8), bytes.decode_float(i * 16 + 12))
	return result

func bytes_to_packed_vector3_array(bytes: PackedByteArray) -> PackedVector3Array:
	if bytes.size() % 12 != 0:
		return []
	var result: PackedVector3Array = []
	var count: int = bytes.size() / 12
	result.resize(count)
	for i in count:
		result[i] = Vector3(bytes.decode_float(i * 12), bytes.decode_float(i * 12 + 4), bytes.decode_float(i * 12 + 8))
	return result

func bytes_to_packed_vector2_array(bytes: PackedByteArray) -> PackedVector2Array:
	if bytes.size() % 8 != 0:
		return []
	var result: PackedVector2Array = []
	var count: int = bytes.size() / 8
	result.resize(count)
	for i in count:
		result[i] = Vector2(bytes.decode_float(i * 8), bytes.decode_float(i * 8 + 4))
	return result

# You can take exemple here to load a regular Array
func bytes_to_vector2_array(bytes: PackedByteArray) -> Array[Vector2]:
	if bytes.size() % 8 != 0:
		return []
	var result: Array[Vector2] = []
	var count: int = bytes.size() / 8
	result.resize(count)
	for i in count:
		result[i] = Vector2(bytes.decode_float(i * 8), bytes.decode_float(i * 8 + 4))
	return result

func write_zip_file(file_name : String, packed : PackedByteArray) -> Error:
	var writer = ZIPPacker.new()
	var err = writer.open(ZipFileName)
	if err != OK:
		prints("error", err)
		return err
	writer.start_file(file_name)
	writer.write_file(packed)
	writer.close_file()
	# close zipfile
	writer.close()
	return OK

func read_zip_file(file_name : String)-> PackedByteArray:
	var reader = ZIPReader.new()
	var err = reader.open(ZipFileName)
	if err != OK:
		prints("error", err)
		return PackedByteArray()
	var res = reader.read_file(file_name)
	reader.close()
	return res

Yes! Thanks you very much :slight_smile:

But I do think they should just make it work similar to FileAccess. Now it’s pretty much up to the user to replicate those functions.