Dateien abschneiden ( [:-x] Operator für Dateien )

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
tomba
User
Beiträge: 21
Registriert: Montag 14. Dezember 2015, 15:53

Frohen 2ten Weihnachtsfeiertag. Hier ein kleines Projekt von mir, da ich so eine Lösung noch nie gefunden hab. Have fun!

Code: Alles auswählen

# Code for shortening files by tomba 2015 
# Usage: cutfromfile(filepath,length)
import os
def percentage(part, whole):
  return 100 * float(part)/float(whole)
def getfreespace(path):
	if(os.name == "nt"):
		import ctypes
		space = ctypes.c_ulonglong(0)
		diskname = path.split("\\")[0]+"\\"
		ctypes.windll.kernel32.GetDiskFreeSpaceExW(ctypes.c_wchar_p(diskname), None, None, ctypes.pointer(space))
		return space.value
	else:
		space = os.statvfs(path)
        return space.f_bavail * space.f_frsize
def cutfromfile(filename,length,chunksize=131072,verbose=True):
	if not(os.path.isfile(filename)):
		if(verbose):print("File not found!")
		return 1
	if(chunksize > 524288):
		if(verbose):print("Too big chunks!")
		return 2
	if(os.path.getsize(filename) * 2 > getfreespace(os.path.abspath(filename)[:-len(filename)+1])):
		if(verbose):print("Too less free space on your disk!")
		return 3
	if(os.path.getsize(filename) <= chunksize * 3):
		fs = open(filename,"rb")
		cnt = fs.read()
		fs.close()
		os.remove(filename)
		nf = open(filename,"wb")
		nf.write(cnt[:-length])
		nf.close()
		return 0
	fs = open(filename,"rb")
	total_len = 0
	while True:
		new_chunk = fs.read(chunksize)
		if not(new_chunk):
			break
		total_len += len(new_chunk)
	fs.close()
	os.rename(filename,filename+".old")
	new_file = open(filename,"wb")
	old_file = open(filename+".old","rb")
	dif = total_len - length
	if(verbose):print("Cutting %s from file with size %s (%s Percent) (%s bytes will remain)") % (str(length),str(total_len),str(int(100-percentage(dif,total_len))),str(int(dif)))
	amount = int(dif/chunksize)
	rest = int(dif % chunksize)
	for x in range(0,amount):
		chunk = old_file.read(chunksize)
		new_file.write(chunk)
	rest_chunk = old_file.read(rest)
	new_file.write(rest_chunk)
	old_file.close()
	new_file.close()
	os.remove(filename+".old")
	if(verbose):print("Completed re-writing")
	return 0
Zuletzt geändert von Anonymous am Samstag 26. Dezember 2015, 21:42, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Science makes you fly to the moon, religion makes you fly into buildings.
BlackJack

@tomba: Erster Eindruck: Boah ist das schwer lesbar. Da fehlen eindeutig Leerzeilen und -zeichen, und Zeilenumbrüche.

Weder ``if`` noch ``not`` sind Funktionen, also sollte man sie nicht so schreiben als wären es welche.

Da es sich um Python 3 handelt braucht es keine Umwandlung mit `float()` wenn man Division verwendet.

Das ermitteln des freien Speicherplatzes ist unnötig, wie es auch das umkopieren der Daten in eine temporäre Datei ist. Es gibt `file.truncate()`.

Diese Fehlerrückgabewerte sollte man durch Ausnahmen ersetzen, denn Ausnahmen wurde erfunden um diese fehleranfälligen Fehlerrückgabewerte loszuwerden.

Du verwendest schon `os.path.getsize()` hast in der gleichen Funktion aber dann noch mal eine Schleife welche die gesamte Datei in Blöcken liest um die Dateigrösse zu ermitteln, bevor sie dann nochmal gelesen wird um sie zu kopieren‽ Das ist reichlich umständlich.

Ungetestet:

Code: Alles auswählen

def truncate_file(filename, length):
    if os.path.getsize(filename) < length:
        with open(filename, 'wb') as file_:
            file_.truncate(length)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@BlackJack: der Dateimodus 'wb' macht die Datei sogar noch ein bißchen kürzer. 'rb+' wäre richtig.
Oder weil der OP ja von hinten abschneiden will:

Code: Alles auswählen

def truncate_file(filename, cut_off):
    with open(filename, 'wb') as file_:
        file_.seek(-cut_off, 2)
        file_.truncate()
@tomba: noch zusätzlich was BlackJack schon angemerkt hat: Windows kennt UNC-Pfade, da funktioniert Dein krudes Verzeichnisbuchstabenabschneiden nicht; ist auch gar nicht nötig, weil GetDiskFreeSpaceExW mit irgendwelchen Verzeichnissen zurecht kommt.
Zeile 23: um an den Verzeichnisnamen zu kommen, gibt es os.dirname, dieses Abschneiden des Dateinamens funktioniert auch nur, wenn man nur relative Pfade verwendet. Das ist auch so ein typisch schöne Fehlermeldung: man will eine Datei kürzen und es wird gemeckert, weil nicht genug Festplattenplatz dafür da ist.
Zeile 30: das Entfernen der Datei ist unnötig, weil sie beim Öffnen mit 'wb' sowieso geleert wird. Dateien sollte man übrigens immer in Kombination mit dem with-Statement öffnen.
Zeile 43: man sollte übrigens prüfen, ob es nicht schon eine Datei mit den Namen filename.old gibt. Die wird sonst ohne Warnung überschrieben.
Zeile 47: Bei String-Formatierungen ist es unnötig, alle Argumente erst in Strings umzuwandeln. format kennt übrigens auch Prozent:

Code: Alles auswählen

print("Cutting {} from file with size {} ({:.0%}) ({} bytes will remain)".format(length,total_len, 1-dif/total_len,dif))
Zeile 48: Ganzzahldivision ist // und wenn man sowohl Division als auch Rest braucht, gibt es divmod.
Statt den ganzen if-verbose-print-Zeilen könntest Du auch logging benutzen.

Die Tipps mit den Zeilenumbrüchen, den Leerzeichen und den unnötigen Klammern solltest Du Dir so schnell wie möglich angewöhnen. Falsche Gewohnheiten lassen sich später nur schwer wieder abgewöhnen. Dass man einiges einfacher oder besser Schreiben kann, soll hier nur als gut gemeinte Ratschläge dienen. Die Fehler und unberücksichtigen Randfälle lassen sich nur durch viele Tests abprüfen. Gerade wenn man mit Dateien spielt, können solche Fehler schnell zu Katastrophen werden. Deshalb ist es ja so wichtig, Testfälle sich zu überlegen und sie auch zu Programmieren. Funktionen schreiben ist der kleinste Teil. Da ist es gut, wenn es schon eine fertige Funktion gibt, die schon ausführlich getestet worden ist.
tomba
User
Beiträge: 21
Registriert: Montag 14. Dezember 2015, 15:53

Vielen Dank für eure ausführliche Hilfe :)

Naja ich habe bisher immer so geschrieben. Meine Projekte funktionieren eigentlich auch nicht schlecht. Aber wenn ihr (bestimmt seid ihr erfahrener) mir da Tipps zur Besserung geben könnt, dann nehme ich die gerne an und probiere die in meine nächsten Projekte zu implementieren.

Danke, tomba
Science makes you fly to the moon, religion makes you fly into buildings.
Antworten