103 votes

Writelines écrit les lignes sans nouvelle ligne, remplit juste le fichier.

J'ai un programme qui écrit une liste dans un fichier. La liste est une liste de lignes délimitées par des tubes et les lignes doivent être écrites dans le fichier comme ceci :

123|GSV|Weather_Mean|hello|joe|43.45
122|GEV|temp_Mean|hello|joe|23.45
124|GSI|Weather_Mean|hello|Mike|47.45

MAIS il leur a écrit cette ligne ahhhh :

123|GSV|Weather_Mean|hello|joe|43.45122|GEV|temp_Mean|hello|joe|23.45124|GSI|Weather_Mean|hello|Mike|47.45

Ce programme a écrit toutes les lignes en une seule ligne sans aucun saut de ligne Cela me fait très mal et je dois trouver comment inverser cela, mais de toute façon, où mon programme se trompe-t-il ici ? Je pensais que write lines devait écrire des lignes dans le fichier plutôt que de tout écrire sur une seule ligne

fr = open(sys.argv[1], 'r') # source file
fw = open(sys.argv[2]+"/masked_"+sys.argv[1], 'w') # Target Directory Location

for line in fr:
    line = line.strip()
    if line == "":
        continue
    columns = line.strip().split('|')
    if columns[0].find("@") > 1:
        looking_for = columns[0] # this is what we need to search
    else:
        looking_for = "Dummy@dummy.com"
    if looking_for in d:
        # by default, iterating over a dictionary will return keys
            new_line = d[looking_for]+'|'+'|'.join(columns[1:])
            line_list.append(new_line)
    else:
        new_idx = str(len(d)+1)
        d[looking_for] = new_idx
        kv = open(sys.argv[3], 'a')
        kv.write(looking_for+" "+new_idx+'\n')
        kv.close()
        new_line = d[looking_for]+'|'+'|'.join(columns[1:])
        line_list.append(new_line)
fw.writelines(line_list)

82voto

abarnert Points 94246

Il s'agit en fait d'un problème assez courant pour les nouveaux venus dans Python, d'autant plus que, dans la bibliothèque standard et les bibliothèques tierces populaires, certaines fonctions de lecture suppriment les sauts de ligne, mais pratiquement aucune fonction d'écriture (à l'exception de la fonction log -) les ajouter.

Donc, il y a beaucoup de code Python qui fait des choses comme :

fw.write('\n'.join(line_list) + '\n')

o

fw.write(line + '\n' for line in line_list)

L'une ou l'autre est correcte, et bien sûr vous pouvez même écrire votre propre fonction writelinesWithNewlines qui résume tout

Mais vous ne devez le faire que si vous ne pouvez pas l'éviter.

Il est préférable que vous puissiez créer ou conserver les nouvelles lignes en premier lieu, comme dans les suggestions de Greg Hewgill :

line_list.append(new_line + "\n")

Et c'est encore mieux si vous pouvez travailler à un niveau plus élevé que celui des lignes de texte brutes, par exemple en utilisant la commande csv dans la bibliothèque standard, comme le suggère esuaro.

Par exemple, juste après avoir défini fw vous pourriez faire ça :

cw = csv.writer(fw, delimiter='|')

Alors, au lieu de ça :

new_line = d[looking_for]+'|'+'|'.join(columns[1:])
line_list.append(new_line)

Tu fais ça :

row_list.append(d[looking_for] + columns[1:])

Et à la fin, au lieu de ça :

fw.writelines(line_list)

Tu fais ça :

cw.writerows(row_list)

Enfin, votre conception est la suivante : "ouvrir un fichier, puis établir une liste de lignes à ajouter au fichier, puis les écrire toutes en même temps". Si vous allez ouvrir le fichier en haut, pourquoi ne pas simplement écrire les lignes une par une ? Que vous utilisiez des écritures simples ou un csv.writer cela vous simplifiera la vie et rendra votre code plus facile à lire. (Parfois, il peut y avoir des raisons de simplicité, d'efficacité ou de correction pour écrire un fichier en une seule fois - mais une fois que vous avez déplacé le fichier open jusqu'à l'extrémité opposée du programme par rapport à la write vous avez pratiquement perdu tous les avantages du tout-en-un).

55voto

Greg Hewgill Points 356191

En la documentation pour writelines() États :

writelines() n'ajoute pas de séparateurs de ligne

Vous devrez donc les ajouter vous-même. Par exemple :

    line_list.append(new_line + "\n")

chaque fois que vous ajoutez un nouvel élément à line_list .

37voto

Brent Foust Points 1786

Comme d'autres l'ont noté, writelines est un terme mal choisi (il n'ajoute ridiculement pas de nouvelles lignes à la fin de chaque ligne).

Pour ce faire, il faut l'ajouter explicitement à chaque ligne :

with open(dst_filename, 'w') as f:
    f.writelines(s + '\n' for s in lines)

9voto

Jossef Harush Points 1656

writelines() n'ajoute pas de séparateurs de ligne. Vous pouvez modifier la liste des chaînes de caractères en utilisant map() pour ajouter un nouveau \n (saut de ligne) à la fin de chaque chaîne.

items = ['abc', '123', '!@#']
items = map(lambda x: x + '\n', items)
w.writelines(items)

7voto

jtschoonhoven Points 486

Comme d'autres l'ont mentionné, et contrairement à ce que le nom de la méthode laisse entendre, writelines n'ajoute pas de séparateurs de ligne. C'est un cas d'école pour un générateur. Voici un exemple artificiel :

def item_generator(things):
    for item in things:
        yield item
        yield '\n'

def write_things_to_file(things):
    with open('path_to_file.txt', 'wb') as f:
        f.writelines(item_generator(things))

Avantages : ajoute les nouvelles lignes explicitement sans modifier les valeurs d'entrée ou de sortie ou faire une concaténation de chaîne désordonnée. Et, surtout, ne crée pas de nouvelles structures de données en mémoire. L'entrée/sortie (écriture dans un fichier) est le moment où ce genre de chose a vraiment de l'importance. J'espère que cela aidera quelqu'un !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X