Czy są jakieś alternatywy dla poniższego kodu:
startFromLine = 141978 # or whatever line I need to jump to
urlsfile = open(filename, "rb", 0)
linesCounter = 1
for line in urlsfile:
if linesCounter > startFromLine:
DoSomethingWithThisLine(line)
linesCounter += 1
Jeśli przetwarzam ogromny plik tekstowy (~15MB)
z liniami o nieznanej, ale różnej długości i muszę przeskoczyć do konkretnej linii, którą liczbę znam z góry? Czuję się źle, przetwarzając je jeden po drugim, kiedy wiem, że mógłbym zignorować przynajmniej pierwszą połowę pliku. Szukasz bardziej eleganckiego rozwiązania, jeśli takie istnieje.
python
text-files
user63503
źródło
źródło
Odpowiedzi:
linecache :
źródło
Nie możesz przeskoczyć do przodu bez wczytania się co najmniej raz w pliku, ponieważ nie wiesz, gdzie są podziały wierszy. Możesz zrobić coś takiego:
źródło
Naprawdę nie masz tak wielu opcji, jeśli linie mają różną długość ... niestety musisz przetworzyć znaki końca linii, aby wiedzieć, kiedy przejdziesz do następnej linii.
Możesz jednak znacznie przyspieszyć to i zmniejszyć zużycie pamięci, zmieniając ostatni parametr na „otwórz” na coś innego niż 0.
0 oznacza, że operacja odczytu pliku jest niebuforowana, co jest bardzo powolne i zajmuje dużo miejsca na dysku. 1 oznacza, że plik jest buforowany wierszami, co byłoby poprawą. Cokolwiek powyżej 1 (powiedzmy 8k .. tj .: 8096 lub więcej) odczytuje fragmenty pliku do pamięci. Nadal masz do niego dostęp
for line in open(etc):
, ale Python działa tylko po trochu naraz, odrzucając każdy buforowany fragment po jego przetworzeniu.źródło
Prawdopodobnie rozpieszcza mnie obfity baran, ale 15 M nie jest ogromny. Czytanie do pamięci
readlines()
jest tym, co zwykle robię z plikami tego rozmiaru. Uzyskanie dostępu do następnej linii jest banalne.źródło
Dziwię się, że nikt nie wspomniał o islice
lub jeśli chcesz mieć całą resztę pliku
lub jeśli chcesz co drugą linię z pliku
źródło
Ponieważ nie ma sposobu na określenie długości wszystkich linii bez ich przeczytania, nie masz innego wyjścia, jak tylko powtórzyć wszystkie linie przed linią startową. Wszystko, co możesz zrobić, to ładnie wyglądać. Jeśli plik jest naprawdę duży, możesz użyć podejścia opartego na generatorze:
Uwaga: w tym podejściu indeks jest zerowy.
źródło
Jeśli nie chcesz czytać całego pliku w pamięci ... może być konieczne wymyślenie innego formatu niż zwykły tekst.
oczywiście wszystko zależy od tego, co próbujesz zrobić i jak często będziesz przeskakiwać przez plik.
Na przykład, jeśli masz zamiar wielokrotnie przeskakiwać do wierszy w tym samym pliku i wiesz, że plik nie zmienia się podczas pracy z nim, możesz to zrobić:
Najpierw przejdź przez cały plik i nagraj „ szukaj lokalizacji "niektórych kluczowych numerów linii (takich jak kiedykolwiek 1000 linii).
Następnie, jeśli chcesz linii 12005, przeskocz do pozycji 12000 (którą zapisałeś), a następnie przeczytaj 5 linii i będziesz wiedzieć są w linii 12005 i tak dalej
źródło
Jeśli znasz z góry pozycję w pliku (raczej numer wiersza), możesz użyć file.seek (), aby przejść do tej pozycji.
Edycja : możesz użyć funkcji linecache.getline (nazwa pliku, lineno) , która zwróci zawartość linii lineno, ale tylko po wczytaniu całego pliku do pamięci. Dobrze, jeśli uzyskujesz losowy dostęp do wierszy z pliku (ponieważ sam Python może chcieć zrobić, aby wydrukować śledzenie), ale nie jest dobry dla pliku o wielkości 15 MB.
źródło
Co generuje plik, który chcesz przetworzyć? Jeśli jest to coś pod twoją kontrolą, możesz wygenerować indeks (w której linii znajduje się pozycja) w momencie dołączania pliku. Plik indeksu może mieć stały rozmiar linii (wypełnione spacjami lub 0 liczb dopełnianych) i na pewno będzie mniejszy. Dzięki temu można je szybko czytać i przetwarzać.
źródło
Miałem ten sam problem (trzeba pobrać konkretną linię z ogromnego pliku).
Z pewnością mogę za każdym razem przeglądać wszystkie rekordy w pliku i zatrzymywać je, gdy licznik będzie równy docelowej linii, ale nie działa to skutecznie w przypadku, gdy chcesz uzyskać liczbę mnogą określonych wierszy. To spowodowało, że główny problem został rozwiązany - jak dotrzeć bezpośrednio do potrzebnego miejsca pliku.
Dowiedziałem się kolejnej decyzji: Najpierw uzupełniłem słownik z pozycją początkową każdego wiersza (klucz to numer wiersza, a wartość - skumulowana długość poprzednich wierszy).
ostatecznie funkcja celu:
t.seek (numer_linii) - polecenie, które wykonuje czyszczenie pliku do początku linii. Tak więc, jeśli następnym razem zatwierdzisz readline - otrzymasz swoją docelową linię.
Stosując takie podejście zaoszczędziłem znaczną część czasu.
źródło
Możesz użyć mmap, aby znaleźć przesunięcie linii. Wydaje się, że MMap jest najszybszym sposobem przetwarzania pliku
przykład:
następnie użyj funkcji f.seek (przesunięcia), aby przejść do potrzebnej linii
źródło
Czy same wiersze zawierają jakieś informacje o indeksie? Gdyby zawartość każdego wiersza brzmiała jak „
<line index>:Data
”, toseek()
podejście mogłoby zostać użyte do przeszukania pliku binarnego, nawet jeśli ilośćData
jest zmienna. Szukałbyś środka pliku, czytał wiersz, sprawdzał, czy jego indeks jest wyższy lub niższy niż ten, którego chcesz, itp.W przeciwnym razie najlepsze, co możesz zrobić, to po prostu
readlines()
. Jeśli nie chcesz czytać wszystkich 15 MB, możesz użyćsizehint
argumentu, aby przynajmniej zamienić wielereadline()
s na mniejszą liczbę wywołań funkcjireadlines()
.źródło
Jeśli masz do czynienia z plikiem tekstowym i opartym na systemie linux , możesz użyć poleceń linux.
Dla mnie to działało dobrze!
źródło
Oto przykład użycia „readlines (sizehint)” do odczytywania fragmentów wierszy naraz. DNS wskazał na to rozwiązanie. Napisałem ten przykład, ponieważ inne przykłady tutaj są zorientowane jednowierszowo.
źródło
Żadna z odpowiedzi nie jest szczególnie satysfakcjonująca, więc oto mały fragment, który pomoże.
Przykładowe użycie:
Wymaga to wykonywania wielu operacji wyszukiwania plików, ale jest przydatne w przypadkach, gdy nie można zmieścić całego pliku w pamięci. Wykonuje jeden wstępny odczyt, aby uzyskać lokalizacje wierszy (więc czyta cały plik, ale nie przechowuje go w całości w pamięci), a następnie przy każdym dostępie szuka pliku po fakcie.
Oferuję powyższy fragment w ramach licencji MIT lub Apache według uznania użytkownika.
źródło
Można użyć tej funkcji, aby zwrócić wiersz n:
źródło