2016-04-07 10 views
1

Ich führe ein Skript, das deutsche Umlaute in Dateinamen ersetzt. Es gibt über 1700 Dateien, für die ich dies tun muss, aber ich bekomme eine Fehlermeldung, dass es zu viele offene Dateien gibt, nachdem das Skript für eine Weile ausgeführt wurde. Hat jemand irgendwelche Ideen, wie das zu beheben ist? Feedback wird sehr geschätzt!Python 2.7 unter Windows - zu viele offene Dateien

Code:

# -*- coding: utf-8 -*- 

''' Script replaces all umlauts in filenames within a root directory and its subdirectories with the English 
    equivalent (ie. ä replaced with ae, Ä replaced with Ae).''' 

import os 
import itertools 
import logging 
from itertools import groupby 

##workspace = u'G:\\Dvkoord\\GIS\\TEMP\\Tle\\Scripts\\Umlaut' 
workspace = u'G:\\Gis\\DATEN' 
log = 'Umlauts.log' 
logPath = r"G:\Dvkoord\GIS\TEMP\Tle\Scripts\Umlaut\Umlauts.log" 
logMessageFormat = '%(asctime)s - %(levelname)s - %(message)s' 


def GetFilepaths(directory): 
    """Function returns a list of file paths in a directory tree using os.walk. Parameter: directory 
    """ 
    file_paths = [] 
    for root, directories, files in os.walk(directory): 
     for filename in files: 
      filepath = os.path.join(root, filename) 
      file_paths.append(filepath) 
## file_paths = list(set(file_paths)) 
    return file_paths 

def uniq(input): 
    output = [] 
    for x in input: 
    if x not in output: 
     output.append(x) 
    return output 

def Logging(logFile, logLevel, destination, textFormat, comment): 
    """Function writes a log file. Parameters: logFile (name the log file w/extension), 
     logLevel (DEBUG, INFO, etc.), destination (path under which the log file will be 
     saved including name and extension), textFormat (how the log text will be formatted) 
     and comment. 
    """ 
    # logging 
    logger = logging.getLogger(__name__) 
    # set log level 
    logger.setLevel(logLevel) 
    # create a file handler for the log -- unless a separate path is specified, it will output to the directory where this script is stored 
    logging.FileHandler(logFile) 
    handler = logging.FileHandler(destination) 
    handler.setLevel(logLevel) 
    # create a logging format 
    formatter = logging.Formatter(textFormat) 
    handler.setFormatter(formatter) 
    # add the handlers to the logger 
    logger.addHandler(handler) 
    logger.info(comment) 


def main(): 
    # dictionary of umlaut unicode representations (keys) and their replacements (values) 
    umlautDictionary = { 
         u'Ä': 'Ae', 
         u'Ö': 'Oe', 
         u'Ü': 'Ue', 
         u'ä': 'ae', 
         u'ö': 'oe', 
         u'ü': 'ue', 
         u'ß': 'ss' 
         } 
    dataTypes = [".CPG", 
       ".dbf", 
       ".prj", 
       ".sbn", 
       ".sbx", 
       ".shp", 
       ".shx", 
       ".shp.xml", 
       ".lyr"] 
    # get file paths in root directory and subfolders 
    filePathsList = GetFilepaths(workspace) 
    # put all filepaths with an umlaut in filePathsUmlaut list 
    filePathsUmlaut = [] 
    for fileName in filePathsList: 
##  print fileName 
     for umlaut in umlautDictionary: 
      if umlaut in os.path.basename(fileName): 
       for dataType in dataTypes: 
        if dataType in fileName: 
##      print fileName 
         filePathsUmlaut.append(fileName) 
    # remove duplicate paths from filePathsUmlaut 
    uniquesUmlauts = uniq(filePathsUmlaut) 

    # create a dictionary for umlaut translation 
    umap = { 
      ord(key):unicode(val) 
      for key, val in umlautDictionary.items() 
      } 
    # use translate and umap dictionary to replace umlauts in file name and put them in the newFilePaths list 
    # without changing any of the umlauts in folder names or upper directories 
    newFilePaths = [] 
    for fileName in uniquesUmlauts: 
     pardir = os.path.dirname(fileName) 
     baseName = os.path.basename(fileName) 
     newBaseFileName = baseName.translate(umap) 
     newPath = os.path.join(pardir, newBaseFileName) 
     newFilePaths.append(newPath) 
    newFilePaths = uniq(newFilePaths) 

    # create a dictionary with the old umlaut path as key and new non-umlaut path as value 
    dictionaryOldNew = dict(itertools.izip(uniquesUmlauts, newFilePaths)) 
    # rename old file (key) as new file (value) 
    for files in uniquesUmlauts: 
     for key, value in dictionaryOldNew.iteritems(): 

      if key == files: 
       comment = '%s'%files + ' wurde als ' '%s'%value + ' umbenannt.' 
       print comment 
       if os.path.exists(value): 
        os.remove(value) 
       os.rename(files, value) 
       Logging(log, logging.INFO, logPath, logMessageFormat, comment) 


if __name__ == '__main__': 
    main() 
+0

können Sie bitte die Fehler posten? – qvpham

+1

Erstellen Sie jedes Mal einen Protokollhandler, wenn Sie eine Schleife erstellen? –

+0

@padraic - yeah, ShadowRanger wies darauf hin, dass das wahrscheinlich das Problem ist. werde es ohne die Protokollierung versuchen und sehen, was ausschüttelt. –

Antwort

4

denke ich das Problem Ihr Logging Funktion ist. Jedes Mal, wenn Sie sich anmelden, erstellen Sie eine neue FileHandler und fügen sie der Gruppe von Handlern hinzu, und Sie tun dies für jede umbenannte Datei, so dass Sie schnell das Limit für geöffnete Dateideskriptoren erreichen. Konfigurieren Sie Ihren Logger einmal, verwenden Sie ihn dann mehrmals, und konfigurieren Sie ihn nicht jedes Mal, wenn Sie ihn verwenden.

Beachten Sie, dass die Ausnahme in Logging möglicherweise nicht ausgelöst wird; Wenn Sie eine Datei unter Windows löschen, müssen Sie sie zum Löschen öffnen, damit Sie Dateien mit Loggern maximal öffnen können, und dann fehlschlagen, wenn Sie versuchen, eine Datei zu löschen.

+0

ah - das macht Sinn, danke. Ich werde es ohne die Protokollierung drehen und sehen, was passiert. –

+0

also, was wäre der beste Weg (basierend auf meinem Code), den Logger einmal zu konfigurieren und ihn dann viele Male zu benutzen, im Gegensatz zu dem, was ich gerade mache? –

+0

@CrazyOtto: Erstellen und konfigurieren Sie 'logger' auf oberster Ebene als globale Funktion, nicht in einer Funktion, und ersetzen Sie Aufrufe von' Logging' nur durch 'logger.info (comment)'. – ShadowRanger

Verwandte Themen