Najłatwiejszy sposób na odczyt / zapis zawartości pliku w Pythonie

83

W Rubim możesz czytać z pliku za pomocą s = File.read(filename). Najkrótszy i najbardziej przejrzysty, jaki znam w Pythonie, to

with open(filename) as f:
    s = f.read()

Czy jest jakiś inny sposób, aby to zrobić, aby był jeszcze krótszy (najlepiej jedna linia) i bardziej czytelny?

Uwaga: początkowo sformułowałem pytanie jako „robię to w jednej linii kodu”. Jak zauważył S.Lott, krótszy nie musi oznaczać bardziej czytelnego. Więc przeformułowałem moje pytanie, aby wyjaśnić, co mam na myśli. Myślę, że kod Ruby jest lepszy i bardziej czytelny niekoniecznie dlatego, że jest to jedna linia kontra dwie (choć to też ma znaczenie), ale także dlatego, że jest to metoda klasowa w przeciwieństwie do metody instancji, która nie stawia pytania o to, kto zamyka plik, jak upewnić się, że zostanie zamknięty, nawet jeśli zostanie zgłoszony wyjątek itp. Jak wskazano w poniższych odpowiedziach, możesz polegać na GC, aby zamknąć plik (czyniąc go tym samym jednowierszowym), ale to jeszcze bardziej pogarsza kod chociaż jest krótszy. Nie tylko dlatego, że nie da się go przenosić, ale też czyniąc to niejasnym.

ibz
źródło
7
Utwórz własną funkcję. Następnie możesz go użyć, aby pobrać zawartość. Połączenie byłoby jedną linią.
Felix Kling
1
Ciekawe, czy instrukcja Ruby również zamyka plik?
dheerosaur
8
-1: Nikt nie wygrywa w Code Golf.
S.Lott,
4
Moje pytanie ma dla mnie sens. Próbuję znaleźć lepszy sposób na zapisanie tych dwóch wierszy (4 wiersze przed withinstrukcją w 2.5). Może jest sposób, może nie ma. Zawsze mogę spróbować się dowiedzieć, prawda? Jeśli ci się to nie podoba, zagłosuj przeciw i przejdź dalej. :)
ibz
1
Zaletą programu File.readlines("filename")jest to, że czyta zawartość pliku, podając jego nazwę. Nigdzie nie ma uchwytu pliku, deskryptora ani obiektu. Wszystkie „odpowiedniki” Pythona, które widziałem, obejmują jawne otwarcie / zamknięcie (lub, co gorsza, niejawne otwarcie, które wymaga jawnego zamknięcia).
Mark Reed,

Odpowiedzi:

12

Jeśli jesteś otwarty na używanie bibliotek, spróbuj zainstalować rozwidloną ścieżkę (z easy_install lub pip).

Następnie możesz:

from path import path
s = path(filename).bytes()

Ta biblioteka jest dość nowa, ale jest to rozwidlenie biblioteki, która od lat unosi się w Pythonie i była dość często używana. Odkąd znalazłem tę bibliotekę lata temu, bardzo rzadko używam os.pathlub w open()ogóle.

snapshoe
źródło
Wygląda na niezłą bibliotekę. Nie zainstaluję tego tylko w tym celu, ale będę o tym pamiętać.
ibz
1
Nie rozumiem, dlaczego była to akceptowana odpowiedź, ponieważ to totalny hack!
nikolay
Wersja forked-path v0.2.3 zainstalowana przez pip 18.6 w systemie Windows nie jest zgodna z Pythonem 3.6.4. Wygląda na to, że format używany dla stałych ósemkowych (np. 0777Zamiast 0o0777) nie jest obsługiwany przez moją obecną wersję Pythona.
Christoffer Soop
+1 do odpowiedzi Eyala Levina . Gdyby pathlib lub pathlib2 istniały, kiedy pierwotnie odpowiadałem na to 8 lat temu, wspomniałbym o nich, a nie forked-path. Od lat nie korzystałem z rozwidlonej ścieżki.
snapshoe
151
with open('x.py') as f: s = f.read()

*** uśmiecha się ***

Mark Tolonen
źródło
1
Po prostu nie ma powodu, aby nie pisać tego tak, jak pierwotnie zrobił OP. Zamiar był jasny.
Mark Tolonen
43

Działa tak samo jak powyżej, ale nie obsługuje błędów:

s = open(filename, 'r').read()
pyfunc
źródło
21
Niezupełnie, twój pozostawia otwarty plik.
Ibz
3
Implementacja CPython zamyka plik, gdy liczba odwołań spadnie do zera, ale jest to szczegół implementacji, na którym nie należy polegać.
Mark Tolonen,
1
To obsługuje błędy; wyjątek zostanie wyrzucony jak zwykle. Nie powoduje to „pozostawienia pliku otwartego”, ale może spowodować opóźnienie zamknięcia pliku w zależności od implementacji GC. Może to być problem (blokowanie w systemie Windows i np. Limity FD w przypadku zapętlania wielu plików), ale to bardzo różni się od pozostawienia otwartego pliku (np. Wyciek pliku).
Glenn Maynard,
11
Jeśli twoim celem projektowym jest „jedna linia kodu”, wdychałeś za dużo Perla i musisz zaplanować trochę czasu na pranie mózgu.
Glenn Maynard,
6
Nie, to wcale nie jest mylące.
Glenn Maynard
37

Użyj pathlib .

Python 3.5 i nowsze:

from pathlib import Path
contents = Path(file_path).read_text()

W przypadku niższych wersji Pythona użyj pathlib2 :

$ pip install pathlib2

Następnie

from pathlib2 import Path
contents = Path(file_path).read_text()

Pisanie jest równie łatwe:

Path(file_path).write_text('my text')
Eyal Levin
źródło
18
contents = open(filename).read()
ars
źródło
9
A kiedy zamykasz plik?
Ibz
1
@ionut bizau - Myślę, że kiedy zwrot open(...)jest zbierany jako śmieci. Niech ktoś mnie poprawi, jeśli się mylę.
detly
1
To jest najkrótsza droga. nie wiem, dlaczego nie ma głosów.
Pritesh Acharya
10

To nie jest Perl; nie chcesz na siłę dopasowywać wartości wielu wierszy kodu do jednej linii. Napisz funkcję, a następnie wywołanie funkcji pobiera jedną linię kodu.

def read_file(fn):
    """
    >>> import os
    >>> fn = "/tmp/testfile.%i" % os.getpid()
    >>> open(fn, "w+").write("testing")
    >>> read_file(fn)
    'testing'
    >>> os.unlink(fn)
    >>> read_file("/nonexistant")
    Traceback (most recent call last):
        ...
    IOError: [Errno 2] No such file or directory: '/nonexistant'
    """
    with open(fn) as f:
        return f.read()

if __name__ == "__main__":
    import doctest
    doctest.testmod()
Glenn Maynard
źródło
5

Powolny, brzydki, specyficzny dla platformy ... ale jednolinijkowy ;-)

import subprocess

contents = subprocess.Popen('cat %s' % filename, shell = True, stdout = subprocess.PIPE).communicate()[0]
eumiro
źródło
4
aaaaaaaaaaargh! (przekroczenie „a”, aby osiągnąć minimalny limit znaków)
Peter Gibson
6
Z pewnością pasuje do ducha pytania ... przewrotne użycie Pythona w celu upodobnienia go do Basha nie jest gorsze niż upodobnienie go do Rubiego lub Perla.
detly
3

Takie proste:

    f=open('myfile.txt')
    s=f.read()
    f.close()

I rób, co chcesz z treścią „s”

PYK
źródło
-1
contents = open(filename)

To daje generator, więc musisz gdzieś zapisać wartości, lub

contents = [line for line in open(filename)]

To sprawia, że ​​zapisanie na liście jawnie zamknij nie jest wtedy możliwe (przynajmniej przy mojej znajomości Pythona).

Tony Veijalainen
źródło
1
a z zawartością = '' .join (linia po linii w otwartym (nazwa pliku)) masz oryginalną zawartość pliku ...
eumiro
Użycie pliku jako iteratora nie zamyka pliku deterministycznie (jakwith robi). Nie może, ponieważ po zakończeniu iteracji nadal można wyszukać plik i ponownie rozpocząć czytanie, co nie zadziała, jeśli iteracja zamknie plik.
Glenn Maynard
@Glenn Ale jeśli używasz generatora do rozumienia list, jak w moim przykładzie, nie można go nawet zamknąć, ponieważ nie ma on nazwy.
Tony Veijalainen
„Brak możliwości zamknięcia” to nie to samo, co „nie trzeba go zamykać”.
Glenn Maynard,
Może tak, ale ty nie wiedziałbym, jak uzyskać dostęp do tego uchwytu pliku z wewnętrznego rozumienia listy. Czy powinno być może polecenie „zakończ wszystkie operacje we / wy, zamknij wszystkie otwarte pliki programu” w Pythonie? A może wystarczyłoby jawne gc dla obiektów plikowych? Uchwyt pliku jest poza zakresem, ponieważ rozumienie listy jest oddzielnym zakresem.
Tony Veijalainen