2009-10-02 10 views
5

Mam aplikację, która generuje duże pliki dziennika> 500 MB.Czy można wyszukiwać i mówić pracę z kodowanymi w UTF-8 dokumentami w Pythonie?

Napisałem niektóre narzędzia w Pythonie, które pozwalają mi szybko przejrzeć plik dziennika i znaleźć interesujące go dane. Ale teraz otrzymuję zestawy danych, w których plik jest zbyt duży, aby załadować go do pamięci.

W ten sposób chcę zeskanować dokument raz, zbudować indeks, a następnie załadować tylko część dokumentu do pamięci, którą chcę obejrzeć na raz.

Działa to dla mnie, gdy otwieram "plik", odczytuję go po jednej linii i zapisuję offset z pliku file.tell(). Mogę następnie wrócić do tej sekcji pliku później z file.seek (offset, 0).

Mój problem polega na tym, że mogę mieć kodowanie UTF-8 w plikach dziennika, więc muszę je otworzyć za pomocą modułu koderów-dekoderów (codecs.open(<filename>, 'r', 'utf-8')). Z otrzymanym obiektem mogę zadzwonić do wyszukiwania i powiedzieć, ale nie pasują do siebie.

Zakładam, że kodeki muszą trochę buforować, czy może zwraca liczby znaków zamiast bajtów z tell?

Czy istnieje sposób obejścia tego?

Odpowiedz

2

Jeśli to prawda, to brzmi to jak błąd lub ograniczenie modułu koderów-dekoderów, ponieważ prawdopodobnie powoduje mylenie bajtów i przesunięć znaków.

Chciałbym użyć zwykłej funkcji open() do otwierania pliku, a następnie seek()/tell() da ci przesunięcia bajtów, które są zawsze spójne. Ilekroć chcesz przeczytać, użyj f.readline().decode('utf-8').

Pamiętaj jednak, że użycie funkcji f.read() może spowodować pojawienie się użytkownika w środku wielobajtowego znaku, co spowoduje błąd dekodowania UTF-8. readline() będzie zawsze działać.

Nie obsługuje to w przejrzysty sposób znacznika kolejności bajtów, ale najprawdopodobniej pliki dziennika nie mają list materiałów.

+0

Ściśle mówiąc, UTF-8 ma tylko jedną możliwą kolejność bajtów i dlatego nie ma zastosowania do znaku kolejności bajtów, więc znacznik kolejności bajtów jest nieprawidłowy dla UTF-8. Mimo to niektóre kodery UTF-8 niepoprawnie poprzedzają znak kolejności bajtów, a niektóre dekodery UTF-8 akceptują dane wejściowe zakodowane za pomocą znaku kolejności bajtu. – yfeldblum

+2

To prawda, że ​​w UTF-8 nie ma kolejności bajtów. Jednak znak kolejności bajtów jest często używany w celu wskazania, że ​​plik jest kodowany w UTF-8; Nie nazwałbym tego użycia "niepoprawnym". – intgr

1

W przypadku UTF-8 nie trzeba otwierać pliku przy pomocy codecs.open. Zamiast tego, jest niezawodny, aby najpierw odczytać plik jako ciąg bajtowy, a dopiero potem dekodować pojedynczą sekcję (wywołując metodę .decode w łańcuchu). Zerwanie pliku na linii granicznej jest bezpieczne; jedyny niebezpieczny sposób na podzielenie go byłby w środku wielobajtowego znaku (który można rozpoznać po wartości bajtu> 128).

0

Aktualizacja: Nie można wykonać seek/tell na obiekcie zwróconym przez codec.open(). Musisz użyć zwykłego pliku i dekodować ciągi znaków do unicodu po przeczytaniu.

Nie wiem, dlaczego to nie działa, ale nie mogę sprawić, żeby działało. Poszukiwanie wydaje się działać tylko raz, na przykład. Następnie musisz zamknąć i ponownie otworzyć plik, co oczywiście nie jest przydatne.

Tell nie używa pozycji znakowych, ale nie pokazuje, gdzie znajduje się twoja pozycja w strumieniu (ale prawdopodobnie tam, gdzie znajduje się bazowy obiekt pliku podczas odczytu z dysku).

Prawdopodobnie z powodu pewnego rodzaju buforowania nie można tego zrobić. Ale deocding po przeczytaniu działa dobrze, więc idź do tego.

1

Wiele z tego, co dzieje się z UTF8 w pythonie ma sens, jeśli spojrzysz na to, jak to zrobiono w Pythonie 3.W twoim przypadku, to będzie zrobić trochę więcej sensu, jeśli czytasz ten rozdział plików w Zanurkuj w Pythonie 3: http://diveintopython3.org/files.html

Krótka go jednak to, że file.seek i file.tell praca z pozycjami bajtów, podczas gdy znaki Unicode może zajmować wiele bajtów. Tak więc, jeśli nie:

f.seek(10) 
f.read(1) 
f.tell() 

Można łatwo dostać coś innego niż 17, w zależności od długości jeden znak czytasz było.