W skrócie: nie można uniknąć 2 kopii za pomocą StringIO.
Niektóre założenia:
- Używasz cStringIO, inaczej byłoby głupie, aby zoptymalizować to dużo.
- To szybkość, a nie wydajność pamięci, której szukasz. Jeśli nie, zobacz rozwiązanie Jakoba Bowyera, lub użyj wariantu używając
file.read(SOME_BYTE_COUNT)
, jeśli twój plik jest binarny.
- Powiedziałeś już o tym w komentarzach, ale dla kompletności: chcesz faktycznie edytować zawartość, a nie tylko ją wyświetlić.
Długa odpowiedź: Ponieważ ciągi python są niezmienne, a bufor StringIO nie jest kopią będą musiały być wykonane wcześniej lub później; w przeciwnym razie zmieniałbyś niezmienny obiekt! Dla tego, co chcesz być możliwe, obiekt StringIO musiałby mieć dedykowaną metodę, która byłaby czytana bezpośrednio z obiektu pliku podanego jako argument. Nie ma takiej metody.
Poza StringIO istnieją rozwiązania, które pozwalają uniknąć dodatkowej kopii. Przy mojej głowie, to odczytać plik bezpośrednio do modyfikowalny tablicy bajtów, bez dodatkowych kopia:
import numpy as np
a = np.fromfile("filename.ext", dtype="uint8")
To może być kłopotliwe do pracy, w zależności od zastosowania, którą zamierzasz, ponieważ jest tablicą wartości od 0 do 255, a nie tablica znaków. Ale jest funkcjonalnie równoważny obiektowi StringIO, a używanie notacji wycinania powinno przydać się tam, gdzie chcesz, przy użyciu np.fromstring
, , np.tofile
. Możesz także potrzebować np.insert
, np.delete
i np.append
.
Jestem pewien, że istnieją inne moduły, które będą robić podobne rzeczy.
timeit:
Ile to wszystko naprawdę materii? Więc, zobaczmy. Zrobiłem plik 100 MB, largefile.bin
. Następnie czytam plik, używając obu metod i zmieniając pierwszy bajt.
$ python -m timeit -s "import numpy as np" "a = np.fromfile('largefile.bin', 'uint8'); a[0] = 1"
10 loops, best of 3: 132 msec per loop
$ python -m timeit -s "from cStringIO import StringIO" "a = StringIO(); a.write(open('largefile.bin').read()); a.seek(0); a.write('1')"
10 loops, best of 3: 203 msec per loop
W moim przypadku użycie StringIO jest o 50% wolniejsze niż użycie numpy.
Wreszcie, dla porównania, edytując plik bezpośrednio:
$ python -m timeit "a = open('largefile.bin', 'r+b'); a.seek(0); a.write('1')"
10000 loops, best of 3: 29.5 usec per loop
Tak, to jest prawie 4500 razy szybciej. Oczywiście bardzo zależy to od tego, co zrobisz z plikiem. Zmiana pierwszego bajtu jest mało reprezentatywna. Ale używając tej metody, masz przewagę nad pozostałymi dwoma, a ponieważ większość systemów operacyjnych ma dobre buforowanie dysków, prędkość może być również bardzo dobra.
(Jeśli nie masz uprawnień do edycji pliku i chcesz uniknąć kosztu wykonania kopii roboczej, istnieje kilka możliwych sposobów zwiększenia prędkości. Jeśli możesz wybrać system plików, Btrfs ma copy-on-write Operacja kopiowania plików - wykonanie aktu pobrania kopii pliku praktycznie natychmiastowego Ten sam efekt można uzyskać, korzystając z migawki dowolnego systemu plików.
Co zamierzasz zrobić z 'stream'? Przeczytaj to?? –
Czy używasz Python 2.x lub 3.x? –
@JohnMachin: Ja też chcę to przeczytać i zmodyfikować. Pytanie jest ogólne o Pythonie, jeśli istnieje różnica między 2.x a 3.x, proszę powiedz – zaharpopov