„Linia zawiera bajt NULL” w czytniku CSV (Python)

84

Próbuję napisać program, który przegląda plik .CSV (input.csv) i przepisuje tylko te wiersze, które zaczynają się od określonego elementu (corrected.csv), zgodnie z listą w pliku tekstowym (output.txt).

Tak wygląda teraz mój program:

import csv

lines = []
with open('output.txt','r') as f:
    for line in f.readlines():
        lines.append(line[:-1])

with open('corrected.csv','w') as correct:
    writer = csv.writer(correct, dialect = 'excel')
    with open('input.csv', 'r') as mycsv:
        reader = csv.reader(mycsv)
        for row in reader:
            if row[0] not in lines:
                writer.writerow(row)

Niestety ciągle otrzymuję ten błąd i nie mam pojęcia, o co chodzi.

Traceback (most recent call last):
  File "C:\Python32\Sample Program\csvParser.py", line 12, in <module>
    for row in reader:
_csv.Error: line contains NULL byte

Podziękowania dla wszystkich ludzi tutaj, którzy nawet doprowadzili mnie do tego punktu.

James Roseman
źródło
Zgaduję, ale wygląda na to, że twój plik input.csv zawiera pustą linię (czy na końcu?). Spróbuj poszukać tego tekstu wyjątku w pliku csvParser.py.
Sam Axe,
Właściwie właśnie przejrzałem plik input.csv i pozbyłem się wszelkich pustych miejsc ... nadal nie mam szczęścia (ten sam błąd).
James Roseman,
Aby wskazać numer linii, proponuję wprowadzić zmienną licznika i zwiększyć ją w for row in readerpętli.
codeape
Nie jestem pewien, jak mam to zrobić, gdy sam program nie zostanie wykonany. Próbowałem dodać licznik i nic innego się nie pokazało, tylko ten sam błąd śledzenia.
James Roseman,
4
Czy w pliku .csv masz bajt NULL? open('input.csv').read().index('\0')jeśli to zrobisz, poda ci offset pierwszego.
retracile

Odpowiedzi:

66

Rozwiązałem podobny problem z łatwiejszym rozwiązaniem:

import codecs
csvReader = csv.reader(codecs.open('file.csv', 'rU', 'utf-16'))

Kluczem było użycie modułu kodeków do otwarcia pliku z kodowaniem UTF-16, kodowań jest dużo więcej, sprawdź dokumentację .

K. David C.
źródło
4
Miałem ten sam problem z plikiem CSV utworzonym w LibreOffice, który został pierwotnie otwarty z pliku Excel .xls. Z jakiegoś powodu LibreOffice zapisał plik CSV jako UTF-16. Możesz stwierdzić, patrząc na pierwsze 2 bajty pliku, jeśli jest to FF FE, to dobry wskaźnik, że jest to UTF-16
Tom Dalton
4
Zauważ, że jeśli twój plik zawiera dane UTF-16, które są poza zakresem ASCII csv.reader() , nie będzie w stanie go obsłużyć, a UnicodeEncodeErrorzamiast tego otrzymasz s.
Martijn Pieters
6
To spowodowało po prostu inny błąd, który został podniesionyUnicodeError: UTF-16 stream does not start with BOM
Cerin,
W moim przypadku tak było 'utf-16le'.
Paweł Szczur
69

Domyślam się, że masz bajt NUL w pliku input.csv. Możesz to sprawdzić za pomocą

if '\0' in open('input.csv').read():
    print "you have null bytes in your input file"
else:
    print "you don't"

Jeśli zrobisz,

reader = csv.reader(x.replace('\0', '') for x in mycsv)

może cię obejść. Może też oznaczać, że masz utf16 lub coś „interesującego” w pliku .csv.

wsteczny
źródło
5
+1 po znalezieniu NULL bajtów w pliku ... niestety teraz mój plik 'corrected.csv' czyta się teraz po japońsku ...
James Roseman
Wygląda na to, że plik .csv nie jest w formacie ASCII. Myślę, że dalsza pomoc będzie wymagała nieco więcej informacji o rzeczywistej zawartości pliku .csv. Czy próbowałeś otworzyć go w edytorze tekstu, takim jak VIM lub Notatnik? Lub bieganie, file input.csvaby zidentyfikować typ pliku?
retracile
Otworzyłem go w Notatniku i wygląda dobrze. Jak powinien wyglądać plik CSV? Odczytuje to samo, co w Google Analytics, ale z ogromnymi zakładkami między danymi.
James Roseman,
Cholera ... czy jest jakiś sposób, aby zastąpić tabulatory przecinkami i sprawić, by działał z programem w Pythonie?
James Roseman,
1
Jeśli CSV rozdzielany jest zakładka należy określić tak: reader = csv.reader(mycsv, delimiter='\t'). Wyobrażam sobie, że czytnik csv pożera cały twój plik, szukając przecinków i docierając do EOF. Ale na pewno masz problem z kodowaniem. Podczas otwierania pliku musisz określić kodowanie.
Steven Rumbalski,
11

Jeśli chcesz zastąpić wartości null czymś, możesz to zrobić:

def fix_nulls(s):
    for line in s:
        yield line.replace('\0', ' ')

r = csv.reader(fix_nulls(open(...)))
Claudiu
źródło
2
Zastąpienie null spacją nie będzie dobrym wyborem. Udało mi się zastąpić pustym ciągiem
Marcelo Assis
Mam pytanie, jak wykorzystałeś plony. Biorąc pod uwagę, że jest to pętla, czy oznacza to, że nadal będzie czytać plik wiersz po wierszu, czy też załaduje go od razu do pamięci?
mnsr
10

Możesz po prostu wbudować generator, aby odfiltrować wartości null, jeśli chcesz udawać, że nie istnieją. Oczywiście zakłada się, że bajty zerowe nie są tak naprawdę częścią kodowania i naprawdę są jakimś błędnym artefaktem lub błędem.

Zobacz (line.replace('\0','') for line in f)poniżej, również prawdopodobnie będziesz chciał otworzyć ten plik w trybie rb.

import csv

lines = []
with open('output.txt','r') as f:
    for line in f.readlines():
        lines.append(line[:-1])

with open('corrected.csv','w') as correct:
    writer = csv.writer(correct, dialect = 'excel')
    with open('input.csv', 'rb') as mycsv:
        reader = csv.reader( (line.replace('\0','') for line in mycsv) )
        for row in reader:
            if row[0] not in lines:
                writer.writerow(row)
woot
źródło
Dzięki! To zadziałało dla plików wyników wyborów NC, które rzeczywiście (!) Używają bajtu zerowego zamiast bajtu „0” w jednej kolumnie. Zobacz dl.ncsbe.gov/ENRS/resultsPCT20161108.zip
nealmcb
7

Dzięki temu dowiesz się, w której linii występuje problem.

import csv

lines = []
with open('output.txt','r') as f:
    for line in f.readlines():
        lines.append(line[:-1])

with open('corrected.csv','w') as correct:
    writer = csv.writer(correct, dialect = 'excel')
    with open('input.csv', 'r') as mycsv:
        reader = csv.reader(mycsv)
        try:
            for i, row in enumerate(reader):
                if row[0] not in lines:
                   writer.writerow(row)
        except csv.Error:
            print('csv choked on line %s' % (i+1))
            raise

Być może to z daniweb byłoby pomocne:

Podczas odczytu z pliku csv pojawia się następujący błąd: „Błąd wykonania! Wiersz zawiera bajt NULL”. Masz jakieś pojęcie o głównej przyczynie tego błędu?

...

OK, rozumiem i pomyślałem, że opublikuję rozwiązanie. Po prostu przysporzył mi żalu ... Użyty plik został zapisany w formacie .xls zamiast .csv Nie złapałem tego, ponieważ sama nazwa pliku miała rozszerzenie .csv, podczas gdy typ był nadal .xls

Steven Rumbalski
źródło
1
Traceback (most recent call last): File "C:\Python32\Sample Program\csvParser.py", line 17, in <module> print ('csv choked on line %s' % (i+1)) NameError: name 'i' is not defined
James Roseman,
Ok. Potem dławi się na pierwszej linii. Uruchom to i opublikuj to, co widzisz:print(open('input.csv', 'r').readlines()[0])
Steven Rumbalski,
Coś fajnego ... ale działa. ÿþ/<To wszystko, co by
wkleił
1
Być może Twój plik csv tak naprawdę nie jest plikiem csv. Zobacz drugą połowę mojej odpowiedzi.
Steven Rumbalski
Och, strzelanie, to może być to, jak mam to naprawić?
Zapisałem
2

Trudny sposób:

Jeśli rozwiniesz się pod Lunuxem, możesz wykorzystać całą moc seda :

from subprocess import check_call, CalledProcessError

PATH_TO_FILE = '/home/user/some/path/to/file.csv'

try:
    check_call("sed -i -e 's|\\x0||g' {}".format(PATH_TO_FILE), shell=True)
except CalledProcessError as err:
    print(err)    

Najbardziej wydajne rozwiązanie dla dużych plików.

Sprawdzono pod kątem Python3, Kubuntu

SergO
źródło
1

Niedawno rozwiązałem ten problem iw moim przypadku był to skompresowany plik, który próbowałem odczytać. Najpierw sprawdź format pliku. Następnie sprawdź, czy zawartość jest tym, do czego odnosi się rozszerzenie.

Daniel Lee
źródło
1

Przekształcenie mojego środowiska linux w czyste, kompletne środowisko UTF-8 zrobiło dla mnie sztuczkę. Spróbuj wykonać następujące czynności w wierszu poleceń:

export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
Philippe Oger
źródło
u mnie też zmiana na UTF-8 rozwiązała problem. W systemie Windows użyłem Notepad ++, aby zmienić format z UTF16 na UTF8. Następnie otworzyłem plik za pomocą libreoffice calc i wyczyściłem dodatkowe linie itp.
Yuval Harpaz
1

To już dawno rozwiązane, ale natknąłem się na tę odpowiedź, ponieważ napotkałem nieoczekiwany błąd podczas odczytu pliku CSV w celu przetworzenia jako dane treningowe w Keras i TensorFlow.

W moim przypadku sprawa była dużo prostsza i warto mieć tego świadomość. Dane generowane w pliku CSV nie były spójne, co spowodowało całkowity brak niektórych kolumn, co wydaje się powodować również ten błąd.

Lekcja: jeśli widzisz ten błąd, sprawdź, czy dane wyglądają tak, jak myślisz!

David Hoelzer
źródło