-2
votes

Faire utiliser la déclaration utilisable pour plusieurs objets jetables

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: xxx

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.

Mon problème est évident par les lignes de code commentées. J'aimerais utiliser un en utilisant Block pour disposer en toute sécurité tous les énumérateurs, mais malheureusement, en utilisant (énumérateurs) ne compile pas. Apparemment, en utilisant 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 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 une option viable dans ce cas?


Mise à jour

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: xxx

la méthode d'extension toduSposables devrait s'assurer qu'en cas d'exception, aucun usage n'est laissé non couplé.


5 commentaires

Les commentaires ne sont pas pour une discussion prolongée; Cette conversation a été Déplacé vers Chat .


Que voulez-vous dire " verrouillé " in " Un fichier verrouillé peut provoquer une exception "?


@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 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 (); 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.


4 Réponses :


2
votes

Je vais suggérer une approche qui utilise des appels récursif vers ZIP pour permettre une énumération parallèle d'un ienumerable normal sans avoir recours à l'utilisation de < Code> ienumerator . xxx

saisissez votre énumérables : xxx

Maintenant, il est simple d'appeler: xxx

Voici une trace d'exécution de ce code contre trois fichiers avec plus de 4 lignes: xxx < p> Notez que les énumérations s'arrêtent lorsqu'ils ont rencontré un en-tête de déséquilibre dans la 4ème ligne du deuxième fichier. Toutes les énumérations se sont ensuite arrêtées.


5 commentaires

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 . Par exemple, si je voulais ajouter des lignes simultanément à tous les fichiers, j'aurais besoin d'un Streamwriter Open Streamwriter 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 . Essayez de remplacer zipperimpl (Ss.skip (1)) avec zipperimpl (Ss.skip (1) .toparray ()) 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 () et, yeap, c'est beaucoup mieux. Maintenant, la surcharge est de 2 secondes à 3000 fichiers et pousse plus lentement.



5
votes

Vous pouvez créer une enveloppe jetable sur votre énumérateurs code>: xxx pré>

et l'utiliser avec l'impact le plus bas sur votre code: p>

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;
    }
}


10 commentaires

J'aime ta solution! Je suppose que en utilisant (nouveaux consommables (énumérateurs)) devrait également fonctionner.


@Theodor Zoulias, vous avez totalement raison. Tant que vous n'avez pas à vous référer à la variable dans le bloc en utilisant le bloc , 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. I Définissez un point d'arrêt à l'intérieur de Dispose 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 méthode' . Quelle ligne?


@Alex, j'ai essayé de définir toutes les lignes de Disposer 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 () , c'est parce qu'une instance d'un n'existe pas où vous obtenez l'exception. Cette exception fait partie du comportement attendu . L'OP veut gérer des fichiers tout ou aucun . C'est largement mentionné dans la question, les réponses et les commentaires ici. Pour énumérer jetable s, vous feriez mieux d'utiliser TODISPOSABLE méthode de ici .


@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é.



1
votes

Création d'un wrapper Idisposable @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 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): xxx

i aussi supprimé .select () et .Distinct () . lors de la vérification des lignes. Le premier itère juste sur le tableau énumérateurs - identique à celui foreach au-dessus de celui-ci, vous énumérez ce tableau deux fois. Crée ensuite une nouvelle liste de lignes et .Distit () énumère dessus.


4 commentaires

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 de ces objets Idisposables 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 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 qui pourrait être utilisée à la place d'un toarray ou tolist dans une requête LINQ, puis être Capable d'utiliser le résultat de cette méthode directement dans un à l'aide de instruction: à l'aide de (énumérateurs) {...} .



2
votes

à la deuxième partie de la question. Si je vous obtiens bien cela devrait être suffisant: xxx

utilisation: xxx

et xxx


8 commentaires

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 .


@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.