Dateinamen in jede Zeile schreiben

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hey zusammen,

ich hab jetzt das Skript und wollte nun doch jede Datei einzelt ändern und nicht alles in eine Datei packen. Da würde ich gern den Ursprungsnamen nehmen und einen Zusazu dran hängen (bspw: "_nameappend"), aber ich bekomme es nicht hin. Habe jetzt eine Datei (new.csv) die jedes Mal geöffnet wird, aber natürlich auch jedes Mal überschrieben wird. Jemand eine Idee?

So ist das Skript mit dem new.csv-Platzhalter:

Code: Alles auswählen

import csv, os, sys
pfad = 'C:/Skripttesten/papererweiterung/1/' # relevanter Pfad mit Dateien
liste_dateiname = os.listdir(pfad) # Pfad zu den txt/csv Dateien 'Pfad'
csv.field_size_limit(250000)
#gesamte_datei = open('C:/papererweiterung1/Gesamt61.csv', "wb")  #öffne die gesamte Datei
for dateiname in liste_dateiname:   # für jedes Element der Variable path 
    liste = [] #erstellt eine leeres Array

    neue_datei = open('C:/Skripttesten/papererweiterung/2/new.csv', "wb")  #öffne die gesamte Datei

    with open(os.path.join(pfad, dateiname), "rb") as f: #öffnet die jeweilige datei
        reader = csv.reader(f, delimiter="\t") #liest die zeilen aus, tabstop getrennt
        next(reader) #überspringt jeweils die erste zeile 
        liste = [] #erstellt eine leeres Array
        for row in reader: 
              ...... 
              writer = csv.writer(neue_datei,  delimiter = "\t").writerows(liste)
Ich dachte, dass sowas in der Art doch gehen müsste:

Code: Alles auswählen

neue_datei = open('C:/Skripttesten/papererweiterung/2/          ‘dateiname + “_new“     .csv', "wb
LG
Kid
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi zusammen,

ich mal wieder :(
Aktuell nutze ich das Skript:

Code: Alles auswählen

# -*- coding: utf-8 -*-
#Das Skript hängt den Datennamen an jedes Datei eines Ordner hinten dran (4 Zellen) und nennt die Datei um 
#!/usr/bin/env python
from __future__ import absolute_import, division, print_function
import csv, os, sys, re
from tempfile import NamedTemporaryFile

pfad = 'C:/Skripttesten/papererweiterung1/60Spalten/' # relevanter Pfad mit Dateien

liste_dateiname = os.listdir(pfad) # Pfad zu den txt/csv Dateien 'Pfad'
csv.field_size_limit(250000)
#gesamte_datei = open('C:/Skripttesten/papererweiterung1/Gesamt60.csv', "wb")  #öffne die gesamte Datei
def main():
        for dateiname in liste_dateiname: 
            full_name = os.path.join(pfad, dateiname)
            temporary_file = NamedTemporaryFile(
                prefix=dateiname, dir=pfad, delete=False
            )
            with temporary_file:
                with open(full_name) as csv_file:
                    compid, nummer, _, subname = dateiname.split("#")
                    csv.writer(temporary_file, delimiter="\t").writerows(
                        
                        row + [""] + [dateiname] + [compid] + [nummer] + [subname] #"splittet" den namen mit der Trennung "#"
                        
                        for row in csv.reader(csv_file, delimiter="\t")
                        )
            os.rename(temporary_file.name, full_name + "_nameadded")
 
if __name__ == '__main__':
    main()
print("Ende - leere Spalte (wegen 60 Spalten anstelle von 61), Dateiname, CompID, Nr und Suchstring wurde bei jeder Zeile ergaenzt und speichert in", pfad)
In diese Zeile

Code: Alles auswählen

row + [""] + [dateiname] + [compid] + [nummer] + [subname] #"splittet" den namen mit der Trennung "#"
füge ich ja in jede Zeile einen leere Wert und die zusätzlichen vier Werte ein. Nun wollte ich aber zusätzlich noch etwas hinzufügen, aber leider klappt es nicht.

An der 58. Stelle jede Zeile steht soetwas ("wos:12184a21878f921") und ich möchte das "wos:" entfernen und die ID als einen zusätzliche Wert hinten dran setzen.

Also eigentlich so:

Code: Alles auswählen

for row in csv_file:
       paperIdOhneWos = row[58].replace ("wos:", "") 
row + [""] + [dateiname] + [compid] + [nummer] + [subname] + [paperIdOhneWos ]#"splittet" den namen mit der Trennung "#"
Aber leider geht es nicht.
Der erste Zeichen nach

Code: Alles auswählen

 row[58].replace ("WOS:", "")
am Anfang der Zeile wird immer als Fehler markiert.

Jemand eine Idee?
kid
BlackJack

@kidchino: Im Quelltext hast Du einen Generatorausdruck stehen, bei dem neuen Fragment aber eine ``for``-Schleife. Du hast jetzt nicht eine ``for``-Schleife an die Stelle eines Arguments in einem Funktionsaufruf geschrieben, oder? Das ist syntaktisch nicht möglich, da dürfen nur Ausdrücke stehen die zu einem Wert ausgewertet werden können. Eben der Wert der dann als Argument an den Aufruf übergeben wird.

Lauter Listen mit jeweils nur einem Element mit ``+`` zusammenfügen ist auch eine nette Idee. Wie kommt man denn bitte auf so etwas? Erstell da doch bitte *eine* Liste welche die Elemente enthält und ”addiere” diese *eine* Liste an `row`.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

@Blackjack.
Danke für die schnelle Antwort.
Diesen Teil hab ich von Dir.

Code: Alles auswählen

 row + [""] + [dateiname]
Dann hab ich einfach weiter ausprobiert und andere Teile drangehängt.
kidchino hat geschrieben:Lauter Listen mit jeweils nur einem Element mit ``+`` zusammenfügen ist auch eine nette Idee. Wie kommt man denn bitte auf so etwas?
Da ich leider außer 1/2 Jahr Informatik (Turbo Pascal) in der 7. Klasse (ist auch schon ein, zwei Tage her) noch nie groß mit Programmieren in Berührung gekommen bin, probiere ich es halt irgendwie aus. Und wenn ich die Daten in der Datenbank habe, bin ich hoffentlich durch.

So wie das Skript im Moment läuft, macht es ja glaube ich das was es soll. Ich kann natürlich bei 4GB Textdateien nicht jeden einzelnen Datensatz testen, also denke ich nur, dass alles läuft.
Gibt es denn ein Problem so wie ich es gemacht habe oder ist es einfach nur unüblich und wenig effizient?

VG
kid
BlackJack

@kidchino: Den Teil hast Du ziemlich sicher nicht von mir, ausser ich war high oder besoffen. :-)
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Code: Alles auswählen

row + [dateiname]
Und eigentlich auch das gesamte Grundgerüst des Skriptes ist von Dir - (1 Seite, 6. Beitrag)
Prosit!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Da hast du wohl zu früh angestoßen ;-) Das passiert nämlich, wenn man blind Code übernimmt und nicht versteht was dieser macht.

Code: Alles auswählen

row + [dateiname]
konkateniert die Liste ``row`` und die Liste ``[dateiname]``. Nun könnte es natürlich sein, dass die zweite Liste auch mehr als ein Element enthalten kann ;-)

Code: Alles auswählen

row + ["", dateiname, compid, nummer, subname, paperIdOhneWos ]
Das Leben ist wie ein Tennisball.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

@EyDu
Danke für die Hilfe.
Aber wieso ist das nun besser? Weniger Fehlerpotential, oder warum?
BlackJack

@kidchino: Weil das andere einfach total hässlicher Murks ist der für jede ``+``Operation eine neue Liste erstellt, da die Elemente der alten Liste und das eine Element der neuen Liste hinein kopiert, dann immer die einelementige Liste wieder wegwirft, und ab dem zweiten ``+`` auch die alte Liste mit den ganzen Elementen wegwirft, und das Spielchen dann mit dem nächsten ``+``-Operator noch mal losgeht.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Ok danke.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Hi zusammen,
ich bin immer noch bzw. schon wieder an dieser Stelle:
kidchino hat geschrieben:

Code: Alles auswählen

def main():
        for dateiname in liste_dateiname: 
            full_name = os.path.join(pfad, dateiname)
            temporary_file = NamedTemporaryFile(
                prefix=dateiname, dir=pfad, delete=False
            )
            with temporary_file:
                with open(full_name) as csv_file:
                    compid, nummer, _, subname = dateiname.split("#")
                    csv.writer(temporary_file, delimiter="\t").writerows(
                        
                        row + ["" + dateiname + compid + nummer + subname] 
                        
                        for row in csv.reader(csv_file, delimiter="\t")
                        )
            os.rename(temporary_file.name, full_name + "_nameadded")
 
if __name__ == '__main__':
    main()
print("Ende - leere Spalte (wegen 60 Spalten anstelle von 61), Dateiname, CompID, Nr und Suchstring wurde bei jeder Zeile ergaenzt und speichert in", pfad)
Bevor hier die eine Liste an row angehängt bzw. die beiden Listen konkateniert [EyDu] werden, möchte ich gern alle Anführungszeichen aus row entfernen.
So klappt es ja normalerweise:

Code: Alles auswählen

row = [cell.replace('\"', 'x') for cell in row]
Aber natürlich nicht hier.
Rein logisch müsste es doch zwischen

Code: Alles auswählen

with open(full_name) as csv_file:
und

Code: Alles auswählen

csv.writer(temporary_file, delimiter="\t").writerows
Also alle Anführungszeichen entfernen nach dem Öffnen aber vor dem schreiben. Würde ja Sinn machen, aber es kommt folgender Fehler:
local variable 'row' referenced before assignment

Ich überlege gerade eine globale Variablen draus zumachen, allerdings weiß ich gar nicht ob das sinnvoll ist.
Jemand ein Idee.
LG
kid
Sirius3
User
Beiträge: 18300
Registriert: Sonntag 21. Oktober 2012, 17:20

@kidchino: Die Anführungszeichen werden normalerweise vom csv-Reader interpretiert, bzw. wenn nötig vom csv-Writer geschrieben. Wenn Du daran etwas änderst, machst Du Deine Datei kaputt. Die Beiträge von EyDu und Blackjack solltest Du nochmal lesen.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

@Sirius3: Das Problem ist, dass ich häufig Werte in einer Liste habe, die Text sind und wo dann Wörrter in Anführungszeichen sind, aber leider fehlerhaft, nämlich bspw. so:

Das ist ein "rotes' ' Haus. (also zwei ' anstelle eines ").

Und wenn das vorkommt, wird das:
falsch --> row + ["" + dateiname + compid + nummer + subname] <--falsch

richtig ist -->

Code: Alles auswählen

row + ["", dateiname, compid, nummer, subname]
nicht richtig ausgeführt, bzw. gar nicht ausgeführt. Wahrscheinlich ja weil das Anführungszeichen nicht geschlossen wird.

Ich hab sonst keine Idee, wie ich sonst mit diesem Fehler umgehen soll.
Sirius3 hat geschrieben:Die Beiträge von EyDu und Blackjack solltest Du nochmal lesen.
Das verstehe ich nicht. Ich denke, dass dies nun mit nur eine Liste ist ["" + dateiname + compid + nummer + subname] richtig ist.

LG
Zuletzt geändert von kidchino am Donnerstag 8. Januar 2015, 15:41, insgesamt 1-mal geändert.
BlackJack

@kidchino: Doch das wird ausgeführt und auch ”richtig”, dem Ausdruck ist es völlig egal ob die Einzelteile Anführungszeichen oder sonst was enthalten. Der Ausdruck selbst ist aber sehr wahrscheinlich nicht das was Du willst weil der etwas macht als Dein Ursprünglicher Code und auch als das was EyDu gezeigt hat. Das ist eine Liste bei Dir, aber was glaubst Du denn wie viele Elemente die enthält und wie genau der Inhalt aussieht‽ Was haben die Werte dort für einen Typ und was bewirkt der ``+``-Operator bei diesem Typ‽

Was die Anführungszeichen angeht musst Du Dir mal klarmachen wie das CSV-Format aufgebaut ist. Wie Trennzeichen (Feld und Datensatz) innerhalb von Feldern geschützt werden, wie die Zeichen zum Schützen von Trennzeichen für Felder und Datensätze selber innerhalb von Feldern dargestellt werden (müssen), und so weiter. Und dann müsstest Du das mit dem Dateiformat vergleichen welches das Werkzeug zum Importieren der Daten in die MySQL-Datenbank erwartet. Diese Formate müssen ganz offensichtlich zusammen passen damit das klappt, also muss man dafür sorgen das Dein Programm das schreibt was dieses Werkzeugen lesen möchte und das dieses Werkzeug das lesen kann was von Deinem Programm geschrieben wird. Und das wird man eher nicht durch raten hinbekommen. Höchstens zufällig, und dann weiss man immer noch nicht ob es tatsächlich geklappt hat, oder irgendwelche Fehler kommentarlos verschluckt wurden und Datensätze unvollständig sind oder fehlen.
Sirius3
User
Beiträge: 18300
Registriert: Sonntag 21. Oktober 2012, 17:20

kidchino hat geschrieben:Das verstehe ich nicht. Ich denke, dass dies nun mit nur eine Liste ist ["" + dateiname + compid + nummer + subname] richtig ist.
Dann Schau EyDus letzten Beitrag nochmal genau an!

Wenn Du keine korrekten Inputdaten hast, kannst Du nicht das csv-Modul zum Lesen benutzen, bzw. solltest Du Dir zuerst ein Programm schreiben, das die Daten überprüft und gegebenenfalls korrigiert.
Überprüfen heißt, alle Zeilen, die seltsam aussehen, ausgeben lassen und sich überlegen, ob man den Fehler automatisiert korrigieren kann, oder es weniger Aufwand ist, das von Hand zu tun.
Erst wenn Du korrekte Inputdaten hast, kannst Du damit weiterarbeiten. Wenn Du versuchst, mit kaputten Daten zu arbeiten, wirst Du bei jedem weiteren Schritt wieder und wieder auf die Schnauze fallen. Viel Spaß dabei.
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Danke euch beiden.
Mist, ja klar.
Ich hatte das von Hand nachgetragen, es muss natrülich ["", dateiname, compid, nummer, subname] heißen.
Sorry!
Sirius3 hat geschrieben:oder es weniger Aufwand ist, das von Hand zu tun.
Es sind ca. 920 falsche Datensätze (Zeilen)dabei, wo ein Fehler auftritt. Per Hand wird das leider nichts.
BlackJack hat geschrieben: klarmachen wie das CSV-Format aufgebaut ist.
Ich bin mir gar nicht sicher, ob es wirklich CSV-Dateien sind. Wenn ich sie mir in Notepad++ ansehe, eine Zeile dann so aussehen: "Wert1" \t "Wert2" \t "Wert3" \t "Wert4" \n\r
Oder sehe ich die Anführungszeichen nicht?

VG
PS
Ich kann auch mal eine Originaldatei vor und nach dem Skript anhängen, wenn es sinnvoll ist.
Dort sind dann nämlich Zeilen wo diese Sachen nicht geschrieben werden ("", dateiname, compid, nummer, subname), also noch vor der MySQL-Datenbank
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

kidchino hat geschrieben: Ich bin mir gar nicht sicher, ob es wirklich CSV-Dateien sind.
CSV heißt doch erstmal nur, dass die Werte (dem Namen entsprechend Komma-getrennt) oder mit nem anderen Trennzeichen getrennt sind. Bei mir halt Tabstop. Aber wann werden denn die Werte in Anführungszeichen gesetzt?
Ich bin mir ziemlich sicher, dass im rohen Inhalt meiner Dateien nur störende Anführungszeichen sind, also keine inhaltlich relevanten.
Oder werde die Anführungszeichen gesetzt, während die Dateien durch Python laufen?
VG
BlackJack

@kidchino: Auch wenn es keinen formalen, verbindlichen Standard gibt, bedeuten Anführungszeichen normalerweise dass alles zwischen den Anführungszeichen der Feldinhalt ist. Das ist zum Beispiel dann wichtig wenn innerhalb des Feldes das Trennzeichen für Felder oder Datensätze vorkommt. Wenn man aber Anführungszeichen im Feldinhalt selbst hat, dann muss man die ja auch noch irgendwie gesondert Kennzeichnen damit die nicht mit den Anführungszeichen um den Feldinhalt verwechselt werden können.

Wie gesagt es gibt keinen Standard, aber ein RFC mit Status ”Entwurf” und eine Arbeitsgruppe beim W3C die auch an einer Spezifikation sitzen, und eben den Quasi-Standard wie ihn viel Software die CSV-Dateien liest und schreibt definiert. Siehe auch https://en.wikipedia.org/wiki/Comma-separated_values
kidchino
User
Beiträge: 91
Registriert: Montag 17. November 2014, 14:18

Okay.
Aber dann kann ich doch einfach alle löschen oder nicht? Ich müsste doch auch alle "x"`s löschen können. Unabhängig von der Sinnhaftigkeit.
Oder kann ich die Anführungszeichen nicht einfach ignorieren als Feldmarkierung?
BlackJack

@kidchino: So grundsätzlich kannst Du nicht alle Anführungszeichen löschen ohne den Inhalt zu verändern. Ich hatte doch gerade beschrieben welchen Zweck die erfüllen. ``"a","b,c","d"`` ist nicht das selbe wie ``a,b,c,d``. Das erste sind drei Felder, das zweite sind vier Felder. Ähnliches gilt für

Code: Alles auswählen

a,"b
c",d
vs.

Code: Alles auswählen

a,b
c,d
Das erste ist *ein* Datensatz mit drei Feldern, das zweite sind zwei Datensätze mit jeweils zwei Feldern.
Antworten