8
votes

Méthode de déplacement de fichier plus rapide autre que FILE.MOVE

J'ai une application de console qui va prendre environ 625 jours à compléter. Sauf s'il y a un moyen de le rendre plus rapide.

Tout d'abord, je travaille dans un répertoire qui compte environ 4 000 000 fichiers, sinon plus. Je travaille dans une base de données qui a une ligne pour chaque fichier, puis certains. P>

Utilisation du SQL est relativement rapide, le goulot d'étranglement est lorsque j'utilise fichier.move () Code> Chaque mouvement prend 18 secondes à compléter. p>

y a-t-il un moyen plus rapide que fichier.move () code>? p>

C'est le goulot d'étranglement: P>

File.Move(Path.Combine(location, fileName), Path.Combine(rootDir, fileYear, fileMonth, fileName));


14 commentaires

Si vous utilisez une base de données quand même, pourquoi avez-vous besoin de 4 000 000 fichiers?


@ Timschmelter C'est à l'origine comment ils l'ont conçue. La base de données abrite des informations du fichier la seule partie que je dois mettre à jour est la colonne de localisation. Cette colonne est ce qui indique à l'application qu'ils utilisent où le document est situé pour l'ouvrir.


Si chaque mouvement prend 18 secondes, quelque chose d'autre est très mal, et ce n'est probablement pas votre utilisation de l'API.


Éventuellement d'intérêt? Copie de fichier asynchrone / Déplacement en C #


Quelle est la taille des fichiers? Combien de temps faut-il pour déplacer un à la main? Est-ce que ceci est déplacé sur un réseau?


@cdhowie qu'est-ce que cela pourrait-il? Il s'agit d'un répertoire unique avec plus de 4 millions de fichiers qui ne sont pas indexés.


@Jameswilson, alors il prend probablement le système d'exploitation tant pour mettre à jour le répertoire contenant.


@DANPICHELMAN La majorité d'entre eux sont 100 kb ou moins, il y a un peu de 1 à 2 mbs. Le programme est écrit sur ma machine qui se rend à une part de réseau et déplacez des fichiers sur cette partage dans une méthode plus organisée.


Y a-t-il une chance que votre code puisse être exécuté sur le serveur qui a les fichiers localement? Pour le moment, vous tirez probablement toutes ces données sur le réseau à votre machine locale, puis de retour sur le réseau pour l'écrire.


@DANPICHELMAN Je peux vérifier cela, mais il faudrait placer VS sur le serveur qui pourrait être possible. Est-ce qu'un aperçu de mon code aide de quelque manière que ce soit, ou est-ce que c'est probablement probablement les 4 millions de fichiers qui sont le goulot d'étranglement sans moyen réel de l'améliorer?


Vous n'avez pas besoin de VS, juste des dll de distribution .NET (qui sont probablement déjà là). Si vous avez accès à un serveur et / ou à un expert en réseau, parlez-leur de la surveillance de la performance de votre machine. Idéalement, vous vous attachez aux E / S sur votre boîte.


Exécuter le code sur la case qui contient les fichiers localement pourraient faire une différence très significative - genre d'eau déplacée dans un tuyau d'incendie vs à travers une paille de soda.


@DANPICHELMAN D'ALRIGHT, je vais parler avec lui, merci pour les conseils. Cela a du sens sur la façon dont cela serait plus rapide.


@DANPICHELMAN a l'air d'être à court d'options. C'est un dispositif NAS et il a dit qu'il ne serait pas possible de l'exécuter localement.


3 Réponses :


14
votes

Il devait passer de la commutation de fichier.Move pour configurer un fichierInfo et utiliser .Moveto a augmenté de manière significative la vitesse.

Il fonctionnera dans environ 35 jours maintenant, au lieu de 625 jours. P>

FileInfo fileinfo = new FileInfo(Path.Combine(location, fileName));
fileinfo.MoveTo(Path.Combine(rootDir, fileYear, fileMonth, fileName));


3 commentaires

C'est de bonnes informations. Semble étrange que ce soit comme ça, cependant. Je pourrais avoir à rechercher pourquoi cela en est ainsi.


@Jimmischel Ouais, j'ai testé cela toute la journée, la vitesse a été un changement cohérent avec ces nombreux fichiers. Tout ce que je pouvais trouver, c'est que le fichier.Move vérifie la permission / la sécurité sur chaque appel, où fileInfo.moveto () ne le vérifie qu'une seule fois. Si vous trouvez quelque chose d'autre que j'aimerais savoir.


Très étrange. Je n'ai trouvé aucune vitesse de vitesse: 10529 MS (32824028 TIKS) Directory.Move, 13358 MS (Tiks) Nouveau fichierInfo (). Déplacer, 10926 MS (34061807 TIKS) File.move (). C'est pour 16385 fichiers



2
votes

18 secondes n'est pas vraiment inhabituelle. NTFS ne fonctionne pas bien lorsque vous avez beaucoup de fichiers dans un seul répertoire. Lorsque vous demandez un fichier, il doit effectuer une recherche linéaire de sa structure de données de répertoire. Avec 1 000 fichiers, cela ne prend pas trop de temps. Avec 10 000 fichiers que vous remarquez. Avec 4 millions de fichiers. . . Oui, ça prend un moment.

Vous pouvez probablement le faire encore plus rapidement si vous pré-charger toutes les entrées de répertoire en mémoire. Ensuite, plutôt que d'appeler le constructeur fileinfo pour chaque fichier, vous venez de la regarder dans votre dictionnaire.

quelque chose comme: xxx < P> Maintenant, lorsque vous recevez un nom de la base de données, vous pouvez simplement le regarder dans le dictionnaire. Cela pourrait très bien être plus rapide que d'essayer de le faire du disque à chaque fois.


2 commentaires

J'ai peur de tester cela comme il aurait besoin de charger 4 millions de fichiers dans le répertoire avant de pouvoir commencer tout travail sur les déplacer. Et puis une fois qu'ils sont dans le dictionnaire, j'aurais toujours besoin d'effectuer un fichier.Move ou FileInfo.moveto () sur le fichier si je ne me trompe pas?


@Jameswilson: Oui, vous auriez toujours besoin de faire le fileinfo.moveto () . L'idée est que la pré-chargement de toutes les entrées vous éliminerait de devoir les rechercher un seul par un. Si 4 millions d'entrées sont un problème de mémoire, je ne sais pas. Je ne sais pas non plus combien de temps il faudrait pour charger, bien que je soupçonne que ce serait beaucoup moins d'une heure. Si le résultat serait plus rapide que vos 35 jours, je ne sais pas avec certitude.



2
votes

Vous pouvez déplacer des fichiers en parallèle et également à l'aide de répertoire.enumeratefiles code> vous donne une liste de fichiers chargés paresseux (de bien sûr, je n'ai pas testé avec 4 000 000 fichiers):

var numberOfConcurrentMoves = 2;
var moves = new List<Task>();
var sourceDirectory = "source-directory";
var destinationDirectory = "destination-directory";

foreach (var filePath in Directory.EnumerateFiles(sourceDirectory))
{
    var move = new Task(() =>
    {
        File.Move(filePath, Path.Combine(destinationDirectory, Path.GetFileName(filePath)));

        //UPDATE DB
    }, TaskCreationOptions.PreferFairness);
    move.Start();

    moves.Add(move);

    if (moves.Count >= numberOfConcurrentMoves)
    {
        Task.WaitAll(moves.ToArray());
        moves.Clear();
    }
}

Task.WaitAll(moves.ToArray());


0 commentaires