Python通过自然排序查找下一个文件

时间:2015-11-11 10:47:18

标签: python path

我正在尝试使用深度变量进行自然排序来查找下一个文件,但我遇到了一些问题。

文件夹结构如下:

tests/
------test1/
-----------test2/
----------------...
----------------30.jpg
----------------31.jpg
-----------test3/
----------------...
----------------30.jpg
----------------31.jpg
-----------1.jpg
------1.jpg

我想在当前项目之前到达下一个或项目,使用前进和后退功能迭代它们。 获取同一级别的项目当前正在工作,也是为了获得最大深度级别的项目。

例如,我想在

上使用向后功能
path=tests/test1/test2/1.jpg 

结果

tests/test1/1.jpg

但是

path=tests/test1/test3/1.jpg 

结果

tests/test1/test2/31.jpg

显然与前向函数相反的结果相反。 我当前的问题是找到下一级别的下一个文件,而不重复自己并构建一个循环,迭代到目前为止工作完全正常的文件夹,但我现在完全停留在这个。

到目前为止我的当前代码:

import os
import re

import wx


class PathSelect(wx.App):
    """
    path select application
    """

    def __init__(self):
        """
        initializing function

        :return:
        """
        super(PathSelect, self).__init__()

    @staticmethod
    def ask_path():
        """
        ask for our starting path

        :return:
        """
        wildcard = ("Image Files (*.*)|*.jpeg;*.jpg;*.png;*.bmp|"
                    "Joint Photographic Experts Group (*.jpeg;*.jpg)|*.jpeg;*.jpg|"
                    "Portable Network Graphics (*.png)|*.png|"
                    "Bitmap (*.bmp)|*.bmp|"
                    "All files (*.*)|*.*")
        dialog = wx.FileDialog(None, "Choose a file", os.getcwd(), "", wildcard, wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
        if dialog.ShowModal() == wx.ID_OK:
            return dialog.GetPath()
        dialog.Destroy()


class PathingAlgorithm(object):
    """
    our pathing algorithm
    """

    def __init__(self, depth=1):
        """
        initializing function

        :return:
        """
        self.depth = depth
        self.image_path = ""

    @staticmethod
    def natural_sort(current_list):
        convert = lambda text: int(text) if text.isdigit() else text.lower()
        alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
        return sorted(current_list, key=alphanum_key)

    def current(self):
        """
        return the current path or ask for the path

        :return:
        """
        if not self.image_path:
            self.image_path = PathSelect.ask_path()
        if self.image_path:
            return self.image_path

    def backward(self, path="", depth=0, ghost=False):
        """
        return path for the previous picture

        :param path:
        :param depth:
        :param ghost:
        :return:
        """
        # max recursion case, break our function here
        if self.depth < depth:
            return None

        depth += 1
        if path == "":
            path = self.image_path
        folder = os.path.dirname(path)
        file_name = os.path.basename(path)
        folder_content = self.natural_sort(os.listdir(folder))
        file_index = folder_content.index(file_name)
        if file_index == 0:
            path = self.backward(folder, depth, ghost)
            # handle max depth case
            if path is None:
                return None
            # get in the same level of the foldertree again if possible
            for x in xrange(depth):
                path_list = os.listdir(path)
                if path_list:
                    path = os.path.join(path, self.natural_sort(path_list)[len(path_list) - 1])
        else:
            path = os.path.join(folder, folder_content[folder_content.index(file_name) - 1])
        if not ghost:
            self.image_path = path
        return path

    def forward(self, path="", depth=0, ghost=False):
        """
        return path for the next picture

        :param path:
        :param depth:
        :return:
        """
        depth += 1
        # max recursion case, break our function here
        if self.depth < depth:
            return None

        # on start use current path, on recursion skip this
        if path == "":
            path = self.image_path

        folder = os.path.dirname(path)
        file_name = os.path.basename(path)
        if os.path.isfile(os.path.join(folder, file_name)):
            folders = os.listdir(folder)
        else:
            folders = [name for name in os.listdir(folder) if os.path.isdir(os.path.join(folder, name))]
        folder_content = self.natural_sort(folders)
        file_index = folder_content.index(file_name)
        if file_index == len(folder_content) - 1:
            if self.depth - 1 < depth:
                files = [name for name in os.listdir(folder) if os.path.isfile(os.path.join(folder, name))]
                if files:
                    return os.path.join(folder, files[0])
            path = self.forward(folder, depth, ghost)
            # handle max depth case
            if path is None:
                return None
            # get in the same level of the foldertree again if possible
            for x in xrange(depth):
                if not os.path.isfile(path):
                    file_list = os.listdir(path)
                    if file_list:
                        path = os.path.join(path, self.natural_sort(file_list)[0])
        else:
            path = os.path.join(folder, folder_content[folder_content.index(file_name) + 1])
        if not ghost:
            self.image_path = path
        return path


if __name__ == "__main__":
    app = wx.App()
    app.MainLoop()
    ps = PathingAlgorithm(depth=3)
    # print ps.current()
    # print ps.backward(ghost=True)
    # print ps.forward(ghost=True)
    print ps.forward(
        path='../tests/test1/test2/31.jpg',
        ghost=True,
    )

感谢您提前提供任何帮助

1 个答案:

答案 0 :(得分:1)

我太专注于递归函数,在排序的文件树上解决它是解决方案,目前不是最好的性能是深度太大而且它想要获取所有文件,但对我的情况来说足够好

def get_file_tree(self, path):
    """
    return a natural sorted file tree and the index of your original file

    :param path:
    :return:
    """
    if not os.path.exists(path):
        return None
    filename = os.path.basename(path)
    basepath = os.path.abspath(os.path.dirname(path))
    for _ in xrange(self.depth):
        path = os.path.abspath(os.path.join(basepath, os.pardir))

    # list all files
    configfiles = [os.path.join(dirpath, f)
                   for dirpath, dirnames, files in os.walk(path)
                   for f in fnmatch.filter(files, '*')]
    # use natural sort for the tree
    configfiles = self.natural_sort(configfiles)
    original_path = os.path.join(basepath, filename)
    original_index = configfiles.index(original_path)
    return configfiles, original_index

def backward(self, path="", ghost=False):
    """
    get the next file of our current or defined path

    :param path:
    :param ghost:
    :return:
    """
    if path == "":
        path = self.image_path
    path = os.path.abspath(path)

    configfiles, original_index = self.get_file_tree(path)
    # if file was non existant or the index was 0 return None
    if original_index is None or original_index == 0:
        return None
    new_path = configfiles[original_index - 1]
    if new_path.count("\\") > path.count("\\"):
        return None
    if not ghost:
        self.image_path = new_path
    return new_path

def forward(self, path="", ghost=False):
    """
    get the next file of our current or defined path

    :param path:
    :param ghost:
    :return:
    """
    if path == "":
        path = self.image_path
    path = os.path.abspath(path)

    configfiles, original_index = self.get_file_tree(path)
    # if file was non existant or was the last file, return None
    if original_index is None or len(configfiles) <= original_index + 1:
        return None
    new_path = configfiles[original_index + 1]
    if not ghost:
        self.image_path = new_path
    return new_path