Skip to content

Commit

Permalink
Faster directory enumeration algorithm
Browse files Browse the repository at this point in the history
Also added support for subdirectories.
Works only on Windows.
  • Loading branch information
tp7 committed Jan 5, 2013
1 parent c8da27f commit 6caabaa
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 7 deletions.
10 changes: 5 additions & 5 deletions font_loader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
from font_loader.font_info import FontInfo, FontStyle
from font_loader.ttf_parser import TTFFont
from font_loader.ttc_parser import TTCFont
from misc import WINDOWS_FONTS_FOLDER, get_app_data_folder
from misc import WINDOWS_FONTS_FOLDER, get_app_data_folder, enumerate_files_in_directory

SUPPORTED_FONTS_EXTENSIONS = {'.ttf', '.otf', '.ttc'}

is_supported_font = lambda x: os.path.splitext(x)[1].lower() in SUPPORTED_FONTS_EXTENSIONS
is_supported_font = lambda x: os.path.splitext(x)[1].lower() in {'.ttf', '.otf', '.ttc'}

class FontLoader(object):
def __init__(self, font_dirs = None, load_system_fonts = True):
Expand Down Expand Up @@ -56,7 +55,8 @@ def get_fonts_for_list(self, font_names):
return found, not_found

def __enumerate_font_files(self, directory):
return [os.path.join(directory, x) for x in filter(is_supported_font, os.listdir(directory))]
files = enumerate_files_in_directory(directory)
return [x['path'] for x in files if is_supported_font(x['path'])]

def __enumerate_system_fonts(self):
system_fonts_paths = self.__enumerate_font_files(WINDOWS_FONTS_FOLDER)
Expand Down Expand Up @@ -90,7 +90,7 @@ def __load_fonts(self, fonts_paths):
if added or removed:
# updating the cache
with open(cache_file, 'w', encoding='utf-8') as file:
file.write(FontInfo.FontInfoJsonEncoder(indent=4).encode(self.fonts))
file.write(FontInfo.FontInfoJsonEncoder().encode(self.fonts))

def discard_cache(self):
cache = FontLoader.get_font_cache_file_path()
Expand Down
42 changes: 40 additions & 2 deletions misc/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import hashlib
import os
import sys

from ctypes import windll, wintypes, byref
from time import time

class cached_property(object):
def __init__(self, func, name=None, doc=None):
Expand All @@ -19,7 +20,6 @@ def __get__(self, obj, type=None):
obj.__dict__[self.__name__] = value
return value


def calculate_md5_for_file(path, block_size=2**20):
md5 = hashlib.md5()
with open(path, 'rb') as file:
Expand All @@ -30,6 +30,44 @@ def calculate_md5_for_file(path, block_size=2**20):
md5.update(data)
return md5.hexdigest()

def enumerate_files_in_directory(directory):
files = []
windows_enumerate_directory(directory, files)
return files

def windows_enumerate_directory(directory, files):
FILE_ATTRIBUTE_DIRECTORY = 0x10
INVALID_HANDLE_VALUE = -1
BAN = (u'.', u'..')

FindFirstFile = windll.kernel32.FindFirstFileW
FindNextFile = windll.kernel32.FindNextFileW
FindClose = windll.kernel32.FindClose

out = wintypes.WIN32_FIND_DATAW()
fldr = FindFirstFile(os.path.join(directory, "*"), byref(out))

if fldr == INVALID_HANDLE_VALUE:
raise ValueError("invalid handle!")
try:
while True:
if out.cFileName not in BAN:
isdir = out.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY

if isdir:
windows_enumerate_directory(os.path.join(directory, out.cFileName), files)
else:
ts = out.ftLastWriteTime
timestamp = (ts.dwLowDateTime << 32) | ts.dwHighDateTime
size = out.nFileSizeLow
path = os.path.join(directory, out.cFileName)
files.append({'path': path, 'size': size, 'mod_date':timestamp})
if not FindNextFile(fldr, byref(out)):
break
finally:
FindClose(fldr)



def flag_enum(name, *names):
#extend frozenset with has_flag method
Expand Down

0 comments on commit 6caabaa

Please sign in to comment.