J'ai un tas de fichiers texte dans un dossier et tous devraient avoir des en-têtes identiques. En d'autres termes, les 100 premières lignes de tous les fichiers doivent être identiques. J'ai donc écrit une fonction pour vérifier cette condition: La raison pour laquelle j'utilise des énumérateurs est une efficacité de la mémoire. Au lieu de charger tous les contenus de fichier en mémoire, j'enregistrer les fichiers en ligne de ligne simultanément jusqu'à ce qu'une inadéquation soit trouvée, ou tous les en-têtes ont été examinés. P> Mon problème est évident par les lignes de code commentées. J'aimerais utiliser un Je viens de me rendre compte que ma fonction a une faille grave. La construction des énumérateurs n'est pas robuste. Un fichier verrouillé peut provoquer une exception, tandis que certains énumérateurs ont déjà été créés. Ces énumérateurs ne seront pas disposés. C'est quelque chose que je veux réparer. Je pense à quelque chose comme ceci: p> la méthode d'extension en utilisant Code>
Block pour disposer en toute sécurité tous les énumérateurs, mais malheureusement, en utilisant (énumérateurs) code> ne compile pas. Apparemment,
en utilisant code> peut gérer qu'un seul objet jetable. Je sais que je peux disposer manuellement les énumérateurs, en enveloppant le tout dans un bloc
enfin code> et en exécutant la logique de disposition dans une boucle enfin, mais semble gênant. Existe-t-il un mécanisme que je pourrais utiliser pour rendre le
à l'aide de l'instruction code> une option viable dans ce cas? P>
toduSposables code> devrait s'assurer qu'en cas d'exception, aucun usage n'est laissé non couplé. p> p>
4 Réponses :
Je vais suggérer une approche qui utilise des appels récursif vers saisissez votre Maintenant, il est simple d'appeler: p> Voici une trace d'exécution de ce code contre trois fichiers avec plus de 4 lignes: p> ZIP code> pour permettre une énumération parallèle d'un
ienumerable normal
énumérables code>: p>
Soulevé pour être une solution alternative ingénieuse pour mon problème spécifique, bien que cela ne résout pas le problème thématique causé par les limitations du à l'aide de la déclaration code>. Par exemple, si je voulais ajouter des lignes simultanément à tous les fichiers, j'aurais besoin d'un Streamwriter Open
Streamwriter de code> pour chaque fichier aurait dû être disposé à la fin et Linq ne pouvait pas m'aider dans ce cas (car LINQ est pour la lecture, ne pas écrire).
J'ai effectué des tests de performance et j'ai observé une surcharge exponentielle de la récursivité. Pour 500 fichiers, la surcharge est d'environ 2 secondes dans ma machine. Pour 1000 fichiers, cela devient 15 secondes. Pour les fichiers de 2000, cela devient 120 secondes, etc.
@Theodorzoulias - Je n'ai fait aucun test de performance. J'essaierais normalement d'éviter les appels de composition Skip code>. Essayez de remplacer
zipperimpl (Ss.skip (1)) code> avec
zipperimpl (Ss.skip (1) .toparray ()) code> et voir si cela modifie la performance.
@Theodorzoulias - Gardez également à l'esprit que les fichiers de 2000 étant lus une ligne à la fois, il se peut qu'il y ait un disque important sur le disque.
J'ai ajouté .toarray () code> et, yeap, c'est beaucoup mieux. Maintenant, la surcharge est de 2 secondes à 3000 fichiers et pousse plus lentement.
Vous pouvez créer une enveloppe jetable sur votre et l'utiliser avec l'impact le plus bas sur votre code: p> énumérateurs code>:
private static bool CheckHeaders(string folderPath, int headersCount)
{
var enumerators = Directory.EnumerateFiles(folderPath)
.Select(f => File.ReadLines(f).GetEnumerator())
.ToArray();
using (var disposable = new DisposableEnumerable(enumerators))
{
for (int i = 0; i < headersCount; i++)
{
foreach (var e in enumerators)
{
if (!e.MoveNext()) return false;
}
var values = enumerators.Select(e => e.Current);
if (values.Distinct().Count() > 1) return false;
}
return true;
}
}
J'aime ta solution! Je suppose que en utilisant (nouveaux consommables (énumérateurs)) code> devrait également fonctionner.
@Theodor Zoulias, vous avez totalement raison. Tant que vous n'avez pas à vous référer à la variable dans le bloc code> en utilisant le bloc code>, vous pouvez le garder anonyme comme ça.
@ALEX, je suis simulant system.io.ioException: 'Le processus ne peut pas accéder au fichier car il est utilisé par un autre processus. Code> I Définissez un point d'arrêt à l'intérieur de
Dispose code> méthode mais je ne peux pas y entrer. Est-ce un comportement normal? Si oui, comment puis-je assurer que les objets ont été disposés?
@DMitry Stepanov, pouvez-vous me donner plus de contex? 'J'ai défini un point d'arrêt à l'intérieur de Dispose code> méthode' i>. Quelle ligne?
@Alex, j'ai essayé de définir toutes les lignes de Disposer code> méthode. I "verrouille" le fichier par une autre application et l'exception se lancent sur la ligne
var céchérateurs = répertoire.enumeratefiles (f => file.readlines (f => fileadlines (F) .betenumerator ()). TOARRAY (); / Code> Alors, c'est pourquoi je ne comprends pas comment fonctionne votre solution.
@DMitry Stepanov, si vous voulez dire, vous ne pouvez pas entrer dans jetatableNeumérable.Dispose () code>, c'est parce qu'une instance d'un n'existe pas où vous obtenez l'exception. Cette exception fait partie du comportement attendu b>. L'OP veut gérer des fichiers tout ou aucun b>. C'est largement mentionné dans la question, les réponses et les commentaires ici. Pour énumérer
jetable code> s, vous feriez mieux d'utiliser
TODISPOSABLE code> méthode de ici A >.
@Alex, je l'ai eu. Merci beaucoup. Très bonne réponse! + 1.
@DMitry Stepanov, merci! Je suis heureux de savoir que mes réponses sont utiles!
@DMitry Stepanov, il n'y aurait pas de réponse sans la question. Je crois que la question est sous-estimée. Alors, pourriez-vous vous remettre aussi?
@Alex, je suis d'accord avec vous. J'ai suscité la question il y a quelques jours et je l'ai même marqué comme mon préféré.
Création d'un wrapper code> Idisposable ID> @Alex suggéré est correct. Il a besoin d'une logique pour éliminer les fichiers déjà ouverts si certains d'entre eux sont verrouillés em> et probablement une logique pour les états d'erreur. Peut-être que quelque chose comme ça (la logique d'état d'erreur est très simple): i aussi supprimé .select () code> et
.Distinct () code>. lors de la vérification des lignes. Le premier itère juste sur le tableau code> énumérateurs code> - identique à celui
foreach code> au-dessus de celui-ci, vous énumérez ce tableau deux fois. Crée ensuite une nouvelle liste de lignes et
.Distit () code> énumère dessus. P> p>
Merci @ Stanopeťko! J'ai suscité votre réponse pour être une solution complète à mon problème spécifique. Il garantit que tous mes énumérateurs sont disposés dans tous les cas. Je ne peux pas la marquer comme la réponse acceptée, car elle manque de généralité. Je m'attends à une solution pouvant être appliquée dans tous les cas où une liste des jetables doit être créée en toute sécurité et enfin disposée.
Bien. La classe wrapper aurait besoin de Créateur i> de ces objets code> Idisposables code> comme une entrée afin qu'il puisse les créer et manipuler des erreurs. Il a besoin d'autres actions pour traiter des articles créés. Mais ces articles peuvent être n'importe quoi si vous le voulez général. Donc, l'action de traitement doit savoir quel type il travaille. Le processus lui-même peut vouloir retourner tout simplement bool. Je crois que tout cela est possible, mais une telle classe d'emballage doit être générique que (probablement plus d'un type générique) et en utilisant ce serait assez compliqué. Ou quel genre de généralité vous attendez-vous?
Faire des sons génériques Wrapper comme une bonne idée! Je suis d'accord que la rendre trop compliquée vaincre le but de cet exercice. Le en utilisant code> est censé exister pour simplifier les choses, non pour les rendre encore plus compliquées!
Idéalement, je voudrais avoir une méthode d'extension todisposables code> qui pourrait être utilisée à la place d'un
toarray code> ou
tolist code> dans une requête LINQ, puis être Capable d'utiliser le résultat de cette méthode directement dans un
à l'aide de code> instruction:
à l'aide de (énumérateurs) {...} code>.
à la deuxième partie de la question. Si je vous obtiens bien cela devrait être suffisant: utilisation: p> et p>
Maintenant, vous avez couvert tous les cas de mon problème, mais contrairement à votre première réponse Celui-ci n'est pas général. Je suis intéressé par une solution générale pouvant être appliquée dans tous les cas où une liste des jetables doit être créée en toute sécurité et enfin disposée. Jusqu'à présent, votre première réponse est mon candidat principal pour devenir accepté. 😃
@Theodor Zoulias, j'ai amélioré la solution pour le rendre générique.
Nous avons un gagnant! J'ai accepté votre première réponse, car elle se tient seule. Celui-ci n'est pas parce qu'il ne contient pas la définition de jetatableenumerable code>.
@Theodor Zoulias, génial, merci! Je suis content que ma solution soit utile.
Merci @alex pour avoir pris le temps de mettre en œuvre une solution. Je m'attendais à ce que cette question soit bien accueillie, mais pour des raisons inconnues se sont avérées assez impopulaires. 😃
@Theodor Zoulias, oui, la situation sur le vote me rend triste. La question est intéressante et utile. Comme je le vois, c'est une bataille. Jeu d'électeurs (y compris moi) vs. Down-voters 4: 7. Pas si mal. Du côté lumineux, il est +6 réputation.
Je suppose que certains descendants peuvent ne pas aimer l'idée de lire de multiples fichiers simultanément, certains peuvent être en désaccord que l'élimination des énumérateurs est requise, et certains peuvent simplement se sentir mal à l'aise de discuter de certaines limites qui ressemblent à une lacune de la langue C #.
@Theodor Zoulias, c'est triste mais vrai. Les gens ont tendance à détester les choses qu'ils sont mal à l'aise avec ou ils ne comprennent pas.
Les commentaires ne sont pas pour une discussion prolongée; Cette conversation a été Déplacé vers Chat .
Que voulez-vous dire " verrouillé i>" in " Un fichier verrouillé peut provoquer une exception i>"?
@Alex je veux dire verrouillé pour la lecture. Par exemple, un fichier déjà ouvert à partir d'une autre application avec le drapeau
FileShare.none code>
entraînera une exception lorsque j'essaie de l'ouvrir à partir de ma candidature.Je vois.
Var Enumerators = Directory.EnumerateFiles (FolderPath) .Chotez (f => {ESSAYER {RETURN FLASE.RADLINES (F) .GETENUMERATOR ();} Catch {Retour NULL;}}). Où (f => F! = null) .toarray (); code> m'a aidé avec des fichiers verrouillés de cette façon.
@Alex Dans ce cas, vous aurez une exception avalée et un énumérateur null. Dans mon cas, je veux être informé qu'un fichier est verrouillé de manière à pouvoir le déverrouiller et d'invoquer à nouveau ma fonction. Une vérification partielle des en-têtes de certains fichiers n'est pas utile pour moi.