Arşiv dosyaları, içinde birden fazla klasörü ve dosyaları birleştirip tek bir dosya olarak bir arada tutabileceğiniz dosya formatlarıdır. Eğer isterseniz bu arşiv dosyalarını sıkıştırarak daha az yer kaplamasını, şifreleyerek yetkisiz kişilerin erişiminden korunmasını sağlayabilirsiniz.

Genellikle yedekleme yapmak ya da internette dosya gönderirken boyuttan tasarruf etmek amacıyla kullanılırlar. En çok kullanılan 2 arşiv dosya türü;

  • Windows tabanlı sistemler için zip
  • Linux tabanlı sistemler için tar arşivleridir.

Python’da dosya ve klasörler üzerinde çalışırken bu arşiv dosyalarını oluşturabilir, okuyabilir veya içindeki dosyaları çıkartabilirsiniz.

Python’da Zip Arşiv Dosyaları

Zip Dosyaları Oluşturmak

Python’da zip dosyaları ile çalışmak normal dosyalar ile çalışma konusuna benzerdir. Bu dosyaları oluşturmak, okumak, içindekileri çıkartmak gibi işlemler için zipfile modülü yardımcı olur. Bu modülün de en çok kullanılan fonksiyonu ZipFile() fonksiyonudur. Dosyalar ile çalışırken kullandığımız open() fonksiyonuna benzer şekilde kullanılır.

Bir zip arşiv dosyası oluşturmak için; önce veri yazma formatında bir arşiv dosyası açarsınız ve sonra bir listedeki dosyaları bu dosyaya yazarsınız.

Örnek üzerinde görmek için bir çalışma klasörü oluşturalım, sonra da içine alt klasör ve dosyalar ekleyelim;

├── main.py
├── demetler/
|   ├── bilgi.txt
|   └── demet1.py
|   ├── demet2.py
|   └── veri.json
|
├── ornek1.py
├── personel-verileri.json

Python kodlarımızı main.py dosyası içine yazacağız ve bu dosya içinde bir arşiv dosyası oluşturarak çalışma klasörümüz içindeki diğer dosyaları ve demetler klasörünü içindeki dosyalar ile birlikte bu arşiv dosyasına yazacağız.

Bunun için alt klasörler ile birlikte tüm dosyaların listesine ihtiyacımız olacak. O halde daha önce edindiğimiz bilgi ile önce bu listeyi oluşturalım. Hangi klasör ve dosyalar ile çalışacağımızı bulmak için ihtiyacımız olan ilk modül hiyerarşik olarak alt klasörleri de tarayabilen glob modülüdür.

glob modülündeki glob() fonksiyonu ile içinde bulunduğumuz klasörde yer alan dosyaları ve alt klasörleri, alt klasörler içindeki dosyaları bulup, oluşturduğumuz listeye append() fonksiyonu ile ekleyelim. Böylece arşivlenecek alt klasör ve dosyalardan oluşan bir listemiz olacak.

Son olarak zipfile modülünün ZipFile() fonksiyonunu kullanarak bağlam yönetici with..as ifadesiyle bir arşiv dosyası açacağız ve bir döngü kullanarak bu listedeki alt klasörlerin ve dosyaların bir arşiv dosyasına yazılmasını sağlayacağız;

import glob
import zipfile

arsivlenecekDosyalar=[]

for belge in glob.iglob("**/*", recursive=True):
  arsivlenecekDosyalar.append(belge)

with zipfile.ZipFile("arsiv.zip", "w") as arsiv:
  for dosya in arsivlenecekDosyalar:
    arsiv.write(dosya)

Python kodumuzu çalıştırdığımızda bize çıktı olarak, çalışma klasörümüz içinde bir arsiv.zip dosyası oluşturacaktır.

Örneğimizde, zip formatında bir arşiv dosyasını “w” yazılabilir formatta açtık. Eğer varolan bir arşiv dosyasını yazılabilir formatta açarsanız, arşivin içindeki mevcut dosyaların silinerek yeni bir arşiv oluşturulmasına neden olursunuz. Buna dikkat ediniz. Ya da yeni bir arşiv dosyası oluşturduğunuzdan emin olmak için mevcut bilginiz ile bu dosyanın daha önce varolup olmadığını kontrol eden bir python kodu ekleyebilirsiniz.

Eğer mevcut bir arşiv dosyasına yeni klasörler ve dosyalar eklemek isterseniz, arşiv dosyasını veri ekleme modunda “a” açarak yapabilirsiniz. Çalışma klasörümüz içinde yeni.txt isimli bir dosya oluşturalım ve mevcut arsiv.zip dosyasına ekleyelim;

with zipfile.ZipFile("arsiv.zip", "a") as arsiv:
  arsiv.write("yeni1.txt")
  arsiv.write("yeni2.txt")

 

Zip Dosyalarını Okumak

Bir zip dosyasını okumak, içindeki dosya ve klasörlerin listesine erişmek anlamını taşır. Daha önceki konuda olduğu gibi bağlam yönetici with..as ifadesiyle arşiv dosyasına erişir ve onu bu sefer okuma “r” modunda açarız.

with zipfile.ZipFile(“arsiv.zip”, “r”) as arsivDosyasi

Böylece elimizde bir ZipFile nesnesi olur. Artık bu ZipFile nesnesine zipfile modülü tarafından sağlanan fonksiyonlar ile işlemler yapabiliriz. Örneğin, arşiv dosyası içindeki klasör ve dosyaların isimlerini liste şeklinde almak için namelist() fonksiyonunu kullanabiliriz;

import zipfile

with zipfile.ZipFile("arsiv.zip") as arsivDosyasi:
  print(arsivDosyasi.namelist())

Çıktı:

['demetler/', 'ornek1.py', 'personel-verileri.json', 'yeni.txt', 'main.py', 'demetler/demet1.py', 'demetler/bilgi.txt', 'demetler/veri.json', 'demetler/demet2.py', 'yeni.txt']

Zip formatında sıkıştırılmış olan arşiv dosyasının içindeki dosyalar hakkında detaylı bilgi almak isterseniz de getinfo() fonksiyonunu kullanabilirsiniz. Bu fonksiyon size dosyanın oluşturulma tarihi, sıkıştırılmış boyutu, arşiv dosyası içindeki tam yolu gibi bilgiler sağlar.

import zipfile

with zipfile.ZipFile("arsiv.zip") as arsivDosyasi:
  demetlerVerisi=arsivDosyasi.getinfo("demetler/veri.json")
  print(demetlerVerisi)
  print(demetlerVerisi.date_time)
  print(demetlerVerisi.compress_size)

Çıktı:

<ZipInfo filename='demetler/veri.json' filemode='-rw-r--r--' file_size=0>
(2020, 12, 4, 19, 9, 24)
0

 

Zip Arşivinden Dosyaları Çıkartmak

Zip olarak arşivlenmiş bir dosya içindeki bir ya da daha fazla dosyayı arşivden çıkartmak için yine zipfile modülünün extract() ve extractall() fonksiyonları kullanılır.

Arşiven çıkarttığınız dosyalar varsayılan olarak mevcut içinde çalıştığınız klasöre çıkartılır ama isterseniz dosyaları çıkartmak istediğiniz konumu parametre olarak belirtebilirsiniz. Eğer dosyaları çıkartmak istediğiniz klasör halihazırda mevcut değilse bu fonksiyonlar onu sizin için oluşturacaktır.

import zipfile

with zipfile.ZipFile("arsiv.zip") as arsiv:
  # Yedekler isimli bir klasör oluşturup,tüm dosyaları içine çıkartsın
  arsiv.extractall("yedekler")
  # Sadece demetler/veri.json dosyasını mevcut klasör içine çıkartsın
  arsiv.extract("demetler/veri.json")

Bu kodları içinde sadece arsiv.zip dosyanızın olduğu bir çalışma klasöründe çalıştırmanızı tavsiye ederim. Çünkü yukarıda yer alan kodları uyguladıysanız eğer çalışma klasörünüz dosya ve klasör açısından bayağı karışık bir duruma gelmiştir artık. O nedenle boş bir çalışma klasöründe arsiv.zip dosyası yanında bu basit kodlarımızı içeren bir python dosyası oluşturun ve çalıştırın. Çıktı olarak mevcut çalışma klasörü altında yedekler isimli bir klasör oluşturularak arşiv içindeki tüm alt klasör ve dosyaların altında yer aldığını göreceksiniz. Ayrıca kodumuzun son satırının çıktısı olarak da demetler isimli bir klasör oluşturularak içinde sadece veri.json dosyasının yer aldığını göreceksiniz.

 

Şifrelenmiş Zip Arşivleri

Eğer üzerinde çalıştığınız zip arşiv dosyası şifre korumalı bir dosya ise, içindeki dosyaları çıkartmak için şifreyi de bir parametre olarak vermelisiniz;

import zipfile

with zipfile.ZipFile("sifreliarsiv.zip") as arsiv:
  # Yedekler isimli bir klasör oluşturup,tüm dosyaları içine çıkartsın
  arsiv.extractall("yedekler",pwd="qwerty")

Bu şekilde zipfile modülü basit olarak bir metin şifresi ile oluşturulmuş zip arşiv dosyalarının içeriğine erişmeniz konusunda size yardımcı olabilir. Ancak zipfile modülü içinde dosyaları şifrelemek için herhangi bir fonksiyon bulunmaz.

Yani Python’ın şifreli arşiv dosyaları oluşturmanızı sağlayan hazır bir modülü yoktur. Bunun için, Shin Aoyama tarafından yazılmış pyminizip modülünü ya da Daniel Hillier tarafından yazılmış olan pyzipper modülünü pip yardımıyla kurarak kullanabilirsiniz.

Her iki modülde oldukça basit ve kullanışlı modüllerdir. Biz burada örnek olarak pyzipper modülünü kullanacağız.

Öncelikle terminalde;

pip install pyzipper

komutunu vererek pyzipper harici modülünün indirilip kurulmasını sağlıyoruz.

import glob, pyzipper

# Önce içinde bulunduğumuz dizini ve alt dizin ile dosyaları bir listeye ekleyelim.
arsivlenecekDosyalar=[]

for belge in glob.iglob("**/*", recursive=True):
  arsivlenecekDosyalar.append(belge)
# Bu listeden bir arşiv dosyası oluşturalım
with pyzipper.AESZipFile("sifreliarsiv.zip", "w") as arsiv:
  for dosya in arsivlenecekDosyalar:
    arsiv.setpassword(b"qwerty")
    arsiv.setencryption(pyzipper.WZ_AES, nbits=128)
    arsiv.write(dosya)

Şifreli zip arşivi oluşturmak için yine with..as bağlam yöneticisi ile bir arsiv nesnesi oluşturuyoruz. Ancak bu sefer pyzipper modülünün AESZipFile fonksiyonunu kullanıyoruz. setpassword() metodu ile şifremizi oluştururken metin değil byte formatında olması için setpassword(b”şifremizi oluşturan her tür karakterler”) formatında yazıyoruz. Daha sonra setencryption() metodu ile şifreleme algoritmasını seçiyoruz. Standart olarak 256 bit olarak şifrelenir ama buradaki gibi kendinizde belirleyebilirsiniz.

Şifreli zip arşivinden klasör ve dosyaları çıkartmak için de yine pyzipper modülünün AESZipFile() fonksiyonu ve tıpkı zipfile modülündekine benzer şekilde extractall() metodunu kullanıyoruz;

import pyzipper

with pyzipper.AESZipFile("sifreliarsiv.zip") as arsiv:
  # Yedekler isimli bir klasör oluşturup,tüm dosyaları içine çıkartsın
  arsiv.extractall("yedekler",pwd=b"qwerty")

 

Python’da Tar Arşiv Dosyaları

Tar Dosyaları Oluşturmak

Python’da arşiv dosyaları ile çalışmak birbirine benzer şekilde gerçekleşir. Ancak kullanılan modüller farklılık gösterir. Zip arşiv dosyalarıyla çalışırken Python’ın dahili momdüllerinden zipfile kullanılırken, tar arşiv dosyalarıyla çalışırken tarfile modülü kullanılır.

import glob, tarfile

arsivlenecekDosyalar=[]

for belge in glob.iglob("**/*", recursive=True):
  arsivlenecekDosyalar.append(belge)

with tarfile.open("arsiv.tar", "w") as arsiv:
  for dosya in arsivlenecekDosyalar:
    arsiv.add(dosya)

Burada da zip arşivlerinde çalışma şeklimize benzer şekilde önce mevcut klasörün yapısını glob modülü ile keşfedip tüm alt klasör ve içindeki dosyaları bir listeye ekledik. Daha sonra with..as bağlam yöneticisi ile oluşturduğumuz arsiv isimli TarFile nesnesini “w” yazma formatında açıp, add() fonksiyonu yardımı ve for..in döngüsü ile listedeki her bir dosyayı tek tek ekledik. Böylece çalışma klasörümüz içinde arsiv.tar dosyamız oluşturulmuş oldu.

Tar arşiv formatı ile çalışırken de yeni bir tar arşivi oluşturmak için yazma “w” formatında  açtığınız dosya ismini dikkatli seçmenizde fayda vardır. Çünkü daha önce de söylediğimiz gibi aynı isimli bir dosya zaten mevcutsa, o dosyayı siler ve yenisini oluşturur.

Eğer mevcut bir tar arşivine yeni dosyalar eklemek isterseniz arşiv dosyasını veri ekleme “a” yetkisi ile açmalısınız. Şimdi çalışma klasörümüzde yeni.txt isimli bir dosya daha oluşturalım ve arsiv.tar dosyamızın içine ekleyelim;

import tarfile

with tarfile.open("arsiv.tar","a") as arsiv:
    arsiv.add("yeni.txt")

Gördüğünüz gibi Python’da bir dosya oluşturup içine metin eklemek ile, bir tar arşivi oluşturup içine dosya eklemek arasında hiç bir fark yok.

Tar dosyalarını sıkıştırmak için; gzip, bzip2 ve lzma sıkıştırma algoritmaları kullanılır. Bu sıkıştırma işlemini uygulamak için arşiv dosyasını oluştururken yazma “w” yetkisinin yanı sıra; gzip ile sıkıştırmak için “w:gz”, lzma ile sıkıştırmak için “w:xz” kullanılır;

import glob, tarfile

arsivlenecekDosyalar=[]

for belge in glob.iglob("**/*", recursive=True):
  arsivlenecekDosyalar.append(belge)

with tarfile.open("arsiv.tar.gz", "w:gz") as arsiv:
  for dosya in arsivlenecekDosyalar:
    arsiv.add(dosya)

Gördüğünüz gibi arşiv dosyasını oluştururken kullandığımız dosya uzantısı ve yazma yetkisini değiştirerek sıkıştırılmış bir arşiv dosyası elde ettik.

Çalışma klasörümüzün standart boyutu 4,4 KB. ve 1 alt klasör ile 10 dosya içeriyor iken;

tar olarak arşivlediğimiz dosyamızın boyutu 30 KB. olarak karşımıza çıkıyor;

gzip ile sıkıştırdığımızda ise sıkıştırılmış arşiv dosyamızın boyutu 1.1 KB.a düşüyor.

Yani dosyaları sıkıştırarak arşivlemek alan bakımından %75 kazanç sağlamış görünüyor. Tabii bu durum arşivlediğiniz dosyanın türüne göre değişiklik gösterir. Metin bazlı dosyalar yüksek sıkıştırma oranlarına sahipken; resim ve video dosyaları halihazırda zaten jpeg ya da mp4 gibi formatlar ile sıkıştırılmış oldukları için ikinci kez arşivlenip sıkıştırılırken alan olarak metinler kadar çok kazanç sağlamayabilirler.  Ancak yine de her tür dosyayı saklarken ya da yedeklerken arşivlemek çoğu bakımdan faydalıdır.

 

Tar Dosyalarını Okumak

Bir arşiv dosyasını okumak demek, içindeki klasör ve dosyaları görüntülemek anlamını taşır. Bunun için dosyayı okuma “r” yetkisi ile açar, getnames() metodu ile içindeki klasör ve dosyaların listesini alırız.

import tarfile

with tarfile.open("arsiv.tar","r") as arsiv:
    print(arsiv.getnames())

Çıktı:

['yeni-arsiv-olustur.py', 'arsive-dosya-ekle.py', 'demetler', 'demetler/bilgi.txt', 'demetler/demet1.py', 'demetler/demet2.py', 'demetler/veri.json', 'personel-verileri.json', 'ornek1.py', 'demetler/bilgi.txt', 'demetler/veri.json', 'demetler/demet2.py', 'demetler/demet1.py', 'yeni.txt']

 

Arşiv dosyalarını açarken kullanabileceğiniz okuma ve yazma yetkileri şu şekildedir;

“r” Sıkıştırılmamış bir arşiv dosyasını okuma modunda açar

“r:gz” gzip sıkıştırmasıyla oluşturulmuş bir arşiv dosyasını okuma modunda açar

“r:bz2” bzip2 sıkıştırmasıyla oluşturulmuş bir arşiv dosyasını okuma modunda açar

“r:xz” lzma sıkıştırmasıyla oluşturulmuş bir arşiv dosyasını okuma modunda açar

 

“w” Sıkıştırılmamış bir arşiv dosyasını yazma modunda açar ya da oluşturur

“w:gz” Bir arşiv dosyasını gzip sıkıştırmasını kullanarak yazma modunda açar ya da oluşturur

“w:xz” Bir arşiv dosyasını lzma sıkıştırmasını kullanarak yazma modunda açar ya da oluşturur

 

“a” Sıkıştırılmamış bir arşiv dosyasını yeni dosya ekleme modunda açar. Buraa dikkat etmeniz gereken nokta, sıkıştırılmamış olmasıdır. Sıkıştırılmış arşiv dosyalarına yeni dosya ekleyemezsiniz. Eğer sıkıştırılmış bir dosyaya yeni bir dosya eklemek isterseniz yeni bir sıkıştırılmış dosya oluşturabilirsiniz.

 

Tar dosyası içindeki klasör ve dosyaların isimlerini görmek için bir döngü kurabilir, tarfile nesnesinin name özelliğini sorgulayabiliriz;

import tarfile

with tarfile.open("arsiv.tar.gz") as arsiv:
    for belge in arsiv:
        print(belge.name)

Çıktı:

yeni-arsiv-olustur.py
arsive-dosya-ekle.py
demetler
demetler/bilgi.txt
demetler/demet1.py
demetler/demet2.py
demetler/veri.json
arsivdeki-dosyalari-goruntule.py
arsiv.tar
personel-verileri.json
yeni.txt
ornek1.py
demetler/bilgi.txt
demetler/veri.json
demetler/demet2.py
demetler/demet1.py

 

Bunun yanısıra arşiv içindeki dosyaların düzenleme tarihi, boyutu gibi meta verileri ile ilgili bilgileri de sorgulayabiliriz;

import tarfile, time

with tarfile.open("arsiv.tar.gz") as arsiv:
    for belge in arsiv:
        print("Dosya Adı:", belge.name)
        print("Son Düzenleme Tarihi:", time.ctime(belge.mtime))
        dosyaByte=int(belge.size)/1000
        print("Dosya Boyutu(KB.):", dosyaByte, " Kb.")
        print("--------------------------------------")

Çıktı:

Dosya Adı: yeni-arsiv-olustur.py
Son Düzenleme Tarihi: Sun Dec 6 00:51:16 2020
Dosya Boyutu(KB.): 0.243 Kb.
--------------------------------------
Dosya Adı: arsive-dosya-ekle.py
Son Düzenleme Tarihi: Sun Dec 6 00:22:10 2020
Dosya Boyutu(KB.): 0.086 Kb.
--------------------------------------
Dosya Adı: demetler
Son Düzenleme Tarihi: Sun Dec 6 00:07:17 2020
Dosya Boyutu(KB.): 0.0 Kb.
--------------------------------------
Dosya Adı: demetler/bilgi.txt
Son Düzenleme Tarihi: Sun Dec 6 00:07:04 2020
Dosya Boyutu(KB.): 0.0 Kb.
--------------------------------------
Dosya Adı: demetler/demet1.py
Son Düzenleme Tarihi: Sun Dec 6 00:07:09 2020
Dosya Boyutu(KB.): 0.0 Kb.
--------------------------------------
Dosya Adı: demetler/demet2.py
Son Düzenleme Tarihi: Sun Dec 6 00:07:13 2020
Dosya Boyutu(KB.): 0.0 Kb.
--------------------------------------
Dosya Adı: demetler/veri.json
Son Düzenleme Tarihi: Sun Dec 6 00:07:17 2020
Dosya Boyutu(KB.): 0.0 Kb.
--------------------------------------
Dosya Adı: arsivdeki-dosyalari-goruntule.py
Son Düzenleme Tarihi: Sun Dec 6 00:37:05 2020
Dosya Boyutu(KB.): 0.088 Kb.
--------------------------------------
Dosya Adı: arsiv.tar
Son Düzenleme Tarihi: Sun Dec 6 00:51:07 2020
Dosya Boyutu(KB.): 30.72 Kb.
--------------------------------------
...

 

Tar Arşivinden Dosyaları Çıkartmak

Bir tar arşivinden klasör ve dosyaları çıkartabilmek için daha önce öğrendiğimiz şekilde extract() ve extractall() fonksiyonları kullanılır. Bunların yanısıra az sonra değineceğimiz extractfile() fonksiyonu vardır.

Bildiğiniz üzere extract() fonksiyonu belirttiğiniz tek bir dosyayı çıkartmak için kullanılırken, tüm dosyaları çalışma klasörü içine ya da belirttiğiniz bir klasöre çıkartmak için extractall() fonksiyonu kullanılır.

import tarfile
# Dosya çıkartmak
with tarfile.open("arsiv.tar.gz","r:gz") as arsiv:
    arsiv.extract("demetler/bilgi.txt")
# Tüm dosyaları çıkartmak
with tarfile.open("arsiv.tar.gz","r:gz") as arsiv:
    arsiv.extractall("yedekler")

extractfile() metodu arşiv içindeki dosyayı fiili olarak çıkartmaz, ancak dosyayı okunur formatta kullanılır hale getirir;

import tarfile
# Arşiv içindeki dosyayı okunur formatta açmak
with tarfile.open("arsiv.tar.gz","r:gz") as arsiv:
    dosya=arsiv.extractfile("demetler/bilgi.txt")
    print(dosya.read())

Çıktı:

b'Bu dosya içine veri eklemiş olalım!...\n'

 

shutil Modülü ile Arşiv Dosyaları ile Çalışmak

Python’da arşiv dosyası oluşturmak için alternatif olarak shutil modülünü de kullanabilirsiniz. Yeni bir arşiv dosyası oluşturmak için make_archive() ve arşiv dosyası içindeki klasör ve dosyaları çıkartmak için unpack_archive() fonksiyonlarına sahiptir. Ayrıca; zip, tar, bztar ve gztar arşiv formatlarını destekler.

Yeni bir arşiv oluşturmak için;

shutil.make_archive(arşivlenme konumu, arşivleme formatı, arşivlenecek dizin)

şablonu kullanılır.

Mevcut bir arşivden klasör ve dosyaları çıkartmak için de;

shutil.unpack_archive(arşiv dosyası, çıkartılacak konum)

şablonu kullanılır.

 

import shutil

shutil.make_archive("yedek/arsiv","gztar")

Yukarıdaki örnek kodumuz çalışma klasörü içinde yedek isimli bir alt klasör oluşturup, içinde arsiv.tar.gz sıkıştırılmış arşiv dosyasını oluşturarak çalışma klasörü altındaki tüm alt klasör ve dosyaları ekler.

 

import shutil

# Sıkıştırılmış arşivi çıkartma
shutil.unpack_archive("yedek/arsiv.tar.gz","tum_dosyalar")

Bu kod ile de, tum_dosyalar isimli bir klasör oluşturarak , yedek klasörü altında bulunan arsiv.tar.gz isimli sıkıştırılmış arşiv dosyasının içeriğini çıkartıyoruz.