2009-11-16 2 views
0

J'écris un programme qui traite des centaines de fichiers lors de son exécution. En ce moment, chaque fichier et le dossier est stocké dans un objet que j'ai créé (il contient le filepath, filetype, taille du fichier, un pointeur vers un décalage dans le fichier, et si elle est un répertoire) et ces objets sont placés dans un NSMutableArray. Un gros problème avec ceci est à la fin du traitement de tous les fichiers, j'ai besoin d'obtenir des statistiques pour tous les fichiers dans chaque dossier. Je fais cela en utilisant 2 boucles imbriquées, et la performance est terrible. Ma question est la suivante: Existe-t-il un moyen plus efficace de stocker une liste de fichiers et de dossiers dans le cacao (autre que NSMutableArray, ensembles, etc.) pour accéder rapidement à tous les dossiers et tous les objets de ces dossiers? Y at-il une structure qui va créer un tableau de dossiers et un tableau de fichiers et de dossiers situés dans ce dossier parent?meilleure structure de données de cacao pour la liste des fichiers

Répondre

3

En ce moment, chaque fichier et le dossier est stocké dans un objet que j'ai créé (il contient le filepath, filetype, filesize, un pointeur vers un offset dans le fichier, et si c'est un répertoire), et ces objets sont placés dans un NSMutableArray .

C'est la bonne solution. Les tableaux sont plus complexes, car vous devez gérer vous-même la gestion de la taille et vous n'avez pas de vérification des limites.

Un gros problème avec ceci est à la fin du traitement de tous les fichiers, j'ai besoin d'obtenir des statistiques pour tous les fichiers dans chaque dossier. Je fais cela en utilisant 2 boucles imbriquées, et la performance est terrible.

Avez-vous profilé en utilisant Shark et/ou Instruments? C'est la première chose que vous devriez vérifier, si ce n'est déjà fait. Le goulot d'étranglement peut ne pas être là où vous pensez que c'est. Arrêtez de lire cette réponse (et toutes les autres réponses) jusqu'à ce que vous ayez profilé. Si vous bloquez le thread principal avec cette tâche, envisagez plutôt d'utiliser NSOperationQueue. Pour chaque élément du niveau supérieur, s'il s'agit d'un fichier, ajoutez une opération qui examine le fichier et, s'il s'agit d'un répertoire, ajoutez une opération qui effectuera la même itération sur le contenu du répertoire. Si vous avez besoin de Snow Leopard, vous trouverez des blocs utiles ici, car vous n'aurez pas à dire explicitement à l'opération directory-inventory quelle file d'attente ajouter les opérations du fichier d'examen.

Vous devriez probablement mettre un couvercle sur le nombre d'opérations de la file d'attente sera exécutée à la fois, de peur que vous finissez par courir trop eux. Mike Ash has details (ce post concerne GCD, mais à partir de Snow Leopard, NSOperationQueue est basé sur GCD).

En supposant que vous affichez un total en cours d'exécution dans votre interface utilisateur, vous pouvez utiliser la principale file d'attente pour les opérations en attente (par blocs) qui peut ajouter de nouvelles informations aux totaux. Si vous prenez en charge Leopard, vous pouvez créer votre propre file d'attente "principale", mais vous devrez exécuter les opérations sur le thread principal vous-même.

Par ailleurs, si vous total de la taille des fichiers, vous devriez considérer si vous voulez uniquify sur inode. Si je lierai durement un fichier de 200 Mio dans trois autres endroits, vous verrez quatre fichiers, mais ils sont tous exactement le même fichier, donc ils ne prennent que 200 MiB, pas 800.

+0

loop-in-a-loop avec recherche linéaire, que ce soit sur C array et à l'aide de multicore, suce encore. C'est l'algorithme O (n²). Il a besoin de construire un arbre ou un index (hachage) pour le tableau. – Kornel

+0

C'est O (n²) si vous examinez à nouveau la liste entière des dossiers dans la boucle interne pour chaque élément de la boucle externe. Ce n'est pas ce qu'il fait: pour chaque dossier qu'il rencontre dans la boucle externe, il examine chaque élément * de ce dossier * dans la boucle interne. Vraisemblablement, il les ajoute à une sorte de file d'attente afin de traiter tous les fichiers; J'ai suggéré de transformer cela en NSOperationQueue. Le problème de performances pourrait, en guise de conjecture, être de paginer des objets empilés, d'où mes suggestions de (1) profil et (2) utiliser NSOperationQueue (ce qui implique un pool autorelease par opération). –

+0

Une table de carte contribuerait à inode uniquification, et un arbre se prémunir contre d'avoir un dossier et l'un de ses ancêtres à la fois dans la liste, mais je ne peux pas voir comment soit cela aiderait dans le cas général des arborescences de répertoires discrets et pas dur liens. –

2

Vous voudrez peut-être aussi considérer une structure arborescente. Vous avez un noeud racine qui correspond au chemin de fichier "/". Ensuite, root a beaucoup d'enfants, chacun pour "/ System", "/ etc", "/ Library", "/ Users", etc.

Lorsque vous ajoutez un nœud dans cet arbre, vous pouvez le faire percoler et ajouter la taille de fichier du nouveau noeud aux parents (de sorte que l'arbre aura toujours la bonne taille de volume dans le noeud racine). Ou vous pouvez le faire calculer la taille que vous avez besoin (récursivement, le plus probable) et le retourner.

En ce qui concerne la récupération des chemins en premier lieu, vous avez probablement trouvé NSFileManager. Vous devriez également jeter un oeil à NSDirectoryEnumerator et le niveau inférieur FSGetCatalogInfoBulk.

1

Utilisez NSMutableDictionary avec le répertoire du fichier comme clé et NSMutableArray comme objet. Vous serez en mesure de parcourir les répertoires rapidement.

Vous pouvez également diviser le répertoire en utilisant le dictionnaire [NSString pathComponents] et l'utilisation de dictionnaires pour tenir chaque partie du chemin (un arbre). Vous pouvez même mélanger des fichiers et des dictionnaires dans l'arborescence et utiliser [foo isKindOfClass:[NSDictionary class]] pour les différencier.

Voici sa version JSON de ce dont je parle (ce qui se traduit bien aux classes de cacao):

/foo/bar/bazfile & /foo/quzfile =

{"foo": { 
    "bar": { 
     "bazfile": fileinfo 
    }, 
    "quzfile": fileinfo 
} 
+0

lire votre réponse a inspiré pour résoudre un autre problème. à votre santé –

Questions connexes