Acceder à une ligne dans fichier txt volumineux 2GB python
Fermémamiemando Messages postés 33024 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 27 mars 2024 - 22 sept. 2022 à 20:19
- Acceder à une ligne dans fichier txt volumineux 2GB python
- Fichier rar - Guide
- Fichier host - Guide
- Fichier iso - Guide
- Aller à la ligne dans une cellule excel - Guide
- Rendre un fichier moins volumineux - Guide
4 réponses
22 sept. 2022 à 14:09
bonjour, n'hésite pas à montrer ton programme, il ne fait peut-être pas ce que tu imagines.
tu veux accéder à une seule ligne dans le fichier?
Décris la séquence des opérations que tu veux effectuer.
Toutes tes lignes ont la même longueur?
Tu peux faire une boucle de readline(), cela évitera le problème mémoire.
Au fait mon but est de faire une dichotomique de hash. Pour un projet ou j'utilise une variante personnalisée des puzzles de merkle, j ai besoin de me rendre compte de la vitesse à laquelle il est possible de casse sha256.
J ai donc imaginé faire un mini programme qui casserai sha256 avec 5 caractères. À la place de faire une bruteforce classique en essayant toutes les combinaison à chaque fois, j'ai créé une liste de 1,66GB contenant tous les hash à partir de mdp à 5 caractères dans cette ordre là:
sha(aaaaa)
sha(aaaab)
sha(aaaac)
...
sha(99999)
En ayant le fichier dejà créé, il est désormais plus rapide de rechercher un hash(X), et d'en déduire X en fonction de l'index du hash dans le fichier (index de la ligne)
Mais pour augmenter encore la vitesse de calcul, j ai pensé faire une recherche dichotomique. J ai créé un fonction qui fonctionne déjà sur des listes python :
def speedfind(liste, el): lst = [0, len(liste) - 1] while lst[1]-lst[0] > 0: interval1 = [lst[0], (lst[1]-lst[0])//2+lst[0]] interval2 = [((lst[1]-lst[0])//2)+lst[0]+1, lst[1]] if liste[interval1[1]] >= int(el): lst = interval1[:] elif liste[interval1[1]] < int(el): lst = interval2[:] if liste[lst[0]] == int(el): return lst[0] else: return None
J ai donc maintenant besoin de l'adapter aux fichiers. Le probleme est justement que j'aurais bespin d'acceder rapidement au contenu d'une ligne du fichier de 1,66GB en utilisant l'index de la ligne. Il fait une methode qui soit relativement rapide afin que la recherche dichotomique apporte quelque chose de plus par rapport à une simple recherche de cas par cas.
(Pour vous répondre, oui, toutes les lignes on la même taille, vu que tous les hash en hexadecimal ont 64 caractères)
Merci d'avoir pris connaissance de ma question, j'espère qu'on m'aidera à trouver une solution.
????
22 sept. 2022 à 14:47
Le fichier ne devrait-il pas être trié par hash, et pas par mot de passe, pour qu'une recherche dichotomique ait un sens?
As-tu envisagé d'utiliser la base de données SQLite, qui indexera les donnés, et fera la recherche dichotomique automatiquement?
Si tu veux vraiment utiliser un fichier: comme les lignes ont toutes la même longueur, tu peux facilement déterminer l'adresse de la donnée qui t'intéresse, et lire le contenu du fichier à partir de cette adresse.
22 sept. 2022 à 15:17
Oui effectivement, les données devraient être triées par hash, j ai réctifié ce que j'ai dit, majs mon message a été posté apres votre réponse, merci.
Dans le cas ou la liste est triés par hash(x), comment puis-je retrouver x sans associer à chaque hash(x) la valeur de x. Je pourais bien sûr asscier x pour chaque hash(x), mais imaginons que j'écrive dans chaque ligne: hash(x) et x Est ce que le fait que x soit ecrit sir la meme ligne à la suite du hash(x) ne risque pas d'impacter in algorithme de tri ? Il me semble que normallement cela devrait fonctionner mais j'ai néanmoins un doute. De plus ça aura pour conséquence d'ajouter encore ~500MB au fichier, surtout que les hahs en hexadecimal "gaspillent un peut de la place sous forme de caractères, car ça va jusqu'à 16. On pourrait donc exprimer 3 caractères d'un hash avec seulement 2 caractères allant de 0 à 64 par exemple plur economiser de la mémoire.
Sinon à propos des bases SQL, je ne sais pas comment les utiliser. Est ce que c'est simple. Si oui je serais curieux de savoir comment les utiliser de manière à ce que ça fasse une recherche automatiquement.
Aussi, est ce que les donnés sont réèlement traitées plus rapidement avec une base SQL qu'avec un simple fichier texte(Je ne sais pas, c est pour ça que je demande).
Merci
22 sept. 2022 à 15:29
Une base de donnée comme SQLite est la solution la plus simple et la plus rapide pour ce genre d'activité.
Ah oui, vous vous demandez sûrement comment la recherche dichotomique peut fonctionner alors que les hashs eux mêmes ne sont pas triés.
Je pensais effectivement utiliser 2 listes, 1 avec les hash(X) triés selon l'ordre des X, et une deuxième liste triée selon les hash(X) eux mêmes.
Je n'ai pas encore réfléchi à comment faire correspondre les 2 listes, si vous avez des idées n'hésitez pas à me les donner pour ça aussi.
En tout cas pour l'instant je cherche déjà une solution pour acceder rapidement à une ligne avec son index
22 sept. 2022 à 15:17
Un exemple:
def readl(fl,lg,linx): fl.seek(linx*lg) return fl.readline() f=open("big.txt","r") l=7 data=True p=0 while data : data=readl(f,l,p) print(data) p += 1
La fonction readl() lit une ligne d'un fichier, lg étant la longueur d'une ligne, et linx l'index de la ligne.
22 sept. 2022 à 16:05
Merci beaucoup, si j'ai bien compris le but est de deplacer le curseur dans la liste à l'endoit que l'on souhaite, puis en retouener la ligne concernée.
Je n'ai pas encore essayé majs celà semble convenir. Par contre est ce que .seek compte le \n comme 1 caractère, 2 caractères, ou est ce qu'il est ignoré ?
22 sept. 2022 à 16:27
Tous les caractères comptent. Un passage à la ligne est encodé comme un ou deux caractères, cela dépend du contenu du fichier.
Modifié le 22 sept. 2022 à 18:28
Bonjour
À mon avis poser des questions pour mettre en place un code servant à casser un mot de passe est borderline par rapport à la charte du forum. Mais bon, comme un mot de passe fait généralement bien plus que 5 caractères et que l'ensemble des caractères n'est généralement pas limités aux chiffres et aux lettres, on peut se consoler en se disant que l'intérêt pratique est limité.
Ensuite la question est un peu étrange.
- Quel est l'intérêt de stocker dans un fichier texte les résultats précalculés (ou même dans une base) ? Les accès disque, c'est lent et ici on parle de (26+10)^5 ~ 60,5 millions de paires (sha1, mot de passe) autant dire quelque chose qui tient largement en mémoire. Si c'est juste éviter de les recalculer, ne serait-il pas plus simple de directement sauver le dictionnaire qui associe les clés et les valeurs dans un dictionnaire par exemple avec pickle. En mémoire, la recherche sera bien plus rapide.
- Rien ne garantit que sha1 soit injective, ce qui signifie qu'en général elle n'est pas inversible (dans ton cas, plusieurs mots de passe peuvent mener au même hash). Qu'est sensé faire le programme dans ce cas ? Il doit juste retourner un mot de passe arbitraire ?
Bref. En admettant qu'on veuille un mot de passe arbitraire et qu'avec un petit alphabet et de petits mots de passe et qu'on se sente l'âme de Trinity, voici à quoi ça peut ressembler :
import pickle from hashlib import sha1 from itertools import product from pprint import pprint ALPHABET = "abcd" # Ensemble des caractères impliqués dans le mot de passe N = 3 # Longueur maximum du le mot de passe FILENAME = "dump.pkl" # Fichier de backup def str_to_sha1(s): return sha1(s.encode()).digest() def passwords(alphabet, n): yield from ( "".join(chars) for i in range(n + 1) for chars in product(*([alphabet] * i)) ) def compute_map_sha1_password(alphabet, n): return { str_to_sha1(password) : password for password in passwords(alphabet, n) } try: with open(FILENAME, "rb") as f: print(f"loading {FILENAME}") map_sha1_password = pickle.load(f) except: map_sha1_password = compute_map_sha1_password(ALPHABET, N) with open(FILENAME, "wb") as f: print(f"saving {FILENAME}") pickle.dump(map_sha1_password, f) pprint(map_sha1_password)
Mais bon. On va pas casser la matrice avec ça.
Bonne chance
Modifié le 22 sept. 2022 à 20:21
Je ne pense pas que sha256 change grand chose à mon message à vrai dire (je pense que tu devrais arriver à remplacer sha1 par sha256 dans le code).
Concernant pour les collisions, heureusement qu'il n'y en a pas dans seulement 36^5 éléments, sinon le nom de fonction de hachage serait un peu galvaudé...
Est-ce que du coup avec le bout de code que je t'ai partagé, ton problème est résolu ?