2

I have hundreds of QGIS projects that have been built over years and many different QGIS versions. Now I need to move them to another server and I want to be able to edit the project files to show the new file paths.

My issue is that I cannot unzip the qgz files because my PC Administrator has not given me access to an unzipping program. Normally, if the file I want to unzip is one recognised by WinZip, then I can right click and choose Extract. But right clicking a qgz file does not give me the Extract option.

My research indicates that earlier qgs files are easy to access, but my issue is about project files created by the 3.0 series of QGIS and the most recent project file version and my IT admin's distrust of my intentions.

How else can I open the project files to access the file paths in the qgs part?

  • So, yes, I have access to an unzipping program - but it only recognises .zip file. I cannot use it to unzip any other zipped format. – Johanna Aug 12 at 1:54
  • 2
    Try [shift] [right-click] and "open with...". Or manually - rename .qgz to .zip, extract zip, change paths, re-zip, rename .zip to .qgz. If you have python skills, you could automate this with os.walk (os.path.walk in python 2x) and zipfile. – user2856 Aug 12 at 2:00
  • Thank you. The [shift][right-click] doesn't do anything for me, but the renaming does. – Johanna Aug 12 at 2:05
5

To fix this manually, rename .qgz to .zip, extract zip, change paths, re-zip, rename .zip to .qgz.

Alternatively, I've hacked together a very basic and very minimally tested python script to do this (Python 3 only unless you modify it):

from fnmatch import filter
from io import BytesIO
from os import (walk, path, rename)
from zipfile import ZipFile, ZIP_DEFLATED


def main(in_dir, old_path, new_path, backup_suffix=None):
    for (dirpath, dirnames, filenames) in walk(in_dir):
        qgzs = filter(filenames, '*.qgz')
        for qgz in qgzs:
            qgz_path = path.join(dirpath, qgz)
            mem_qgz = BytesIO()
            with ZipFile(qgz_path, 'r') as in_qgz, ZipFile(mem_qgz, 'w', compression=ZIP_DEFLATED) as tmp_qgz:
                for f in in_qgz.infolist():
                    data = in_qgz.read(f.filename).decode('UTF-8')
                    if f.filename.endswith('.qgs'):
                        data = data.replace('source="{}'.format(old_path), 'source="{}'.format(new_path))
                    tmp_qgz.writestr(f.filename, data)

            if backup_suffix is not None:
                backup_suffix = backup_suffix if backup_suffix.startswith('.') else '.' + backup_suffix
                try:
                    rename(qgz_path, qgz_path + backup_suffix)
                except FileExistsError as err:
                    print('Unable to backup file, skipping {} ({})'.format(qgz_path, err))
                    continue

            with open(qgz_path, 'wb') as out_qgz:
                out_qgz.write(mem_qgz.getvalue())


if __name__ == '__main__':
    backup_suffix = '.orig'  # Don't overwrite orig .qgz (just in case...), append ".orig"
    in_dir = r'D:\Temp'

    old_path = 'D:\\'  # 2 trailing backslashes on Windows, 1 forward for Unix like paths
    new_path = r'C:\\'

    main(in_dir, old_path, new_path, backup_suffix)

Note: the path changes are a kludge and rely on a simple search and replace, but the zipped .qgs file is actually XML and really should be parsed as such.

  • 1
    I edited your answer to include the manual method you mentioned in the comments above. Thank you, that's an excellent tip. I had no idea you could do that. – csk Aug 12 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.