Wie lese ich jeweils ein einzelnes Zeichen aus einer Datei in Python?

78

Kann mir jemand sagen, wie ich das machen kann?

kaushik
quelle

Antworten:

89
with open(filename) as f:
  while True:
    c = f.read(1)
    if not c:
      print "End of file"
      break
    print "Read a character:", c
jchl
quelle
41
Da dies jeweils ein Byte liest, schlägt dies nicht bei Nicht-ASCII-Codierungen fehl?
David Chouinard
3
Fragen und Antworten sind verwirrende Zeichen- und Bytekonzepte. Wenn sich die Datei in einer einzelnen Byte-pro-Zeichen-Codierung wie Ascii und vielen anderen befindet, lesen Sie ein einzelnes Zeichen, indem Sie einen einzelnen Byte-großen Block lesen. Wenn die Codierung andernfalls mehr als ein einzelnes Byte pro Zeichen erfordert, sind Sie es Lesen Sie nur ein einzelnes Byte, kein einzelnes Zeichen.
Basel Shishani
2
Korrekt. Deshalb result = open(filename).read()lese ich oft resultZeichen für Zeichen.
Shiva
3
Zu David Chouinards Frage: Dieses Snippet funktioniert in Python 3 korrekt mit einer Datei in UTF-8-Codierung. Wenn Sie beispielsweise eine Datei in Windows-1250-Codierung haben, ändern Sie einfach die erste Zeile in with open(filename, encoding='Windows-1250') as f:
SergO
1
Und um SergO zu ergänzen, kann open(filename, "r")vs open(filename, "rb")zu einer unterschiedlichen Anzahl von Iterationen führen (zumindest was Python 3 betrifft ). Der "r" -Modus kann mehrere Bytes lesen, um zu ermitteln, cob das entsprechende Sonderzeichen vorhanden ist.
dcc310
40

Öffnen Sie zuerst eine Datei:

with open("filename") as fileobj:
    for line in fileobj:  
       for ch in line: 
           print ch
Raj
quelle
Einverstanden scheint dies der pythonischere Weg zu sein. Würde dies nicht auch die Nicht-ASCII-Codierung behandeln?
Ron7
16
Ein Grund, warum Sie eine Datei zeichenweise lesen können, ist, dass die Datei zu groß ist, um in den Speicher zu passen. Bei der obigen Antwort wird jedoch davon ausgegangen, dass jede Zeile in den Speicher passt.
CS
Bearbeitet, um mit Python 3
16

Ich mag die akzeptierte Antwort: Sie ist unkompliziert und erledigt die Arbeit. Ich möchte auch eine alternative Implementierung anbieten:

def chunks(filename, buffer_size=4096):
    """Reads `filename` in chunks of `buffer_size` bytes and yields each chunk
    until no more characters can be read; the last chunk will most likely have
    less than `buffer_size` bytes.

    :param str filename: Path to the file
    :param int buffer_size: Buffer size, in bytes (default is 4096)
    :return: Yields chunks of `buffer_size` size until exhausting the file
    :rtype: str

    """
    with open(filename, "rb") as fp:
        chunk = fp.read(buffer_size)
        while chunk:
            yield chunk
            chunk = fp.read(buffer_size)

def chars(filename, buffersize=4096):
    """Yields the contents of file `filename` character-by-character. Warning:
    will only work for encodings where one character is encoded as one byte.

    :param str filename: Path to the file
    :param int buffer_size: Buffer size for the underlying chunks,
    in bytes (default is 4096)
    :return: Yields the contents of `filename` character-by-character.
    :rtype: char

    """
    for chunk in chunks(filename, buffersize):
        for char in chunk:
            yield char

def main(buffersize, filenames):
    """Reads several files character by character and redirects their contents
    to `/dev/null`.

    """
    for filename in filenames:
        with open("/dev/null", "wb") as fp:
            for char in chars(filename, buffersize):
                fp.write(char)

if __name__ == "__main__":
    # Try reading several files varying the buffer size
    import sys
    buffersize = int(sys.argv[1])
    filenames  = sys.argv[2:]
    sys.exit(main(buffersize, filenames))

Der von mir vorgeschlagene Code entspricht im Wesentlichen Ihrer akzeptierten Antwort: Lesen Sie eine bestimmte Anzahl von Bytes aus der Datei. Der Unterschied besteht darin, dass zuerst ein guter Datenblock gelesen wird (4006 ist eine gute Standardeinstellung für X86, aber Sie können 1024 oder 8192 ausprobieren; ein beliebiges Vielfaches Ihrer Seitengröße), und dann werden die Zeichen in diesem Block ausgegeben einzeln.

Der Code, den ich präsentiere, kann für größere Dateien schneller sein. Nehmen wir zum Beispiel den gesamten Text von Krieg und Frieden von Tolstoi . Dies sind meine Timing-Ergebnisse (Mac Book Pro unter OS X 10.7.4; so.py ist der Name, den ich dem eingefügten Code gegeben habe):

$ time python so.py 1 2600.txt.utf-8
python so.py 1 2600.txt.utf-8  3.79s user 0.01s system 99% cpu 3.808 total
$ time python so.py 4096 2600.txt.utf-8
python so.py 4096 2600.txt.utf-8  1.31s user 0.01s system 99% cpu 1.318 total

Jetzt: Nehmen Sie die Puffergröße nicht 4096als universelle Wahrheit; Schauen Sie sich die Ergebnisse an, die ich für verschiedene Größen (Puffergröße (Bytes) gegenüber Wandzeit (Sek.)) erhalte:

   2 2.726 
   4 1.948 
   8 1.693 
  16 1.534 
  32 1.525 
  64 1.398 
 128 1.432 
 256 1.377 
 512 1.347 
1024 1.442 
2048 1.316 
4096 1.318 

Wie Sie sehen können, können Sie bereits früher Gewinne sehen (und meine Timings sind wahrscheinlich sehr ungenau). Die Puffergröße ist ein Kompromiss zwischen Leistung und Speicher. Der Standardwert von 4096 ist nur eine vernünftige Wahl, aber wie immer zuerst messen.

Escualo
quelle
9

Python selbst kann Ihnen dabei im interaktiven Modus helfen:

>>> help(file.read)
Help on method_descriptor:

read(...)
    read([size]) -> read at most size bytes, returned as a string.

    If the size argument is negative or omitted, read until EOF is reached.
    Notice that when in non-blocking mode, less data than what was requested
    may be returned, even if no size parameter was given.
Mattias Nilsson
quelle
6
Ich stimme dem Gefühl zu, aber vielleicht ist dies besser als Kommentar zum OP geeignet?
Mike Boers
2
Könnte sein, aber ich denke, der ganze Text würde in einem Kommentar chaotisch aussehen.
Mattias Nilsson
8

Gerade:

myfile = open(filename)
onecaracter = myfile.read(1)
Joaquin
quelle
5

Ich habe heute eine neue Redewendung dafür gelernt, als ich Raymond Hettingers Transforming Code in Beautiful, Idiomatic Python sah :

import functools

with open(filename) as f:
    f_read_ch = functools.partial(f.read, 1)
    for ch in iter(f_read_ch, ''):
        print 'Read a character:', repr(ch) 
Michael Kropat
quelle
3

Lesen Sie einfach ein einzelnes Zeichen

f.read(1)
David Sykes
quelle
3

Sie sollten versuchen f.read(1), was definitiv richtig und das Richtige ist.

Johan Kotlinski
quelle
2

Dies wird auch funktionieren:

with open("filename") as fileObj:
    for line in fileObj:  
        for ch in line:
            print(ch)

Es geht durch jede Zeile in der Datei und jedes Zeichen in jeder Zeile.

Pro Q.
quelle
0
f = open('hi.txt', 'w')
f.write('0123456789abcdef')
f.close()
f = open('hej.txt', 'r')
f.seek(12)
print f.read(1) # This will read just "c"
user1489833
quelle
3
Willkommen bei Stackoverflow! Sie sollten näher darauf eingehen - warum ist dies eine Antwort?
Davidkonrad
0

Um eine Ergänzung zu erstellen: Wenn Sie eine Datei lesen, die eine sehr große Zeile enthält, die Ihr Gedächtnis beschädigen könnte, sollten Sie sie in einen Puffer einlesen und dann jedes Zeichen ausgeben

def read_char(inputfile, buffersize=10240):
    with open(inputfile, 'r') as f:
        while True:
            buf = f.read(buffersize)
            if not buf:
                break
            for char in buf:
                yield char
        yield '' #handle the scene that the file is empty

if __name__ == "__main__":
    for word in read_char('./very_large_file.txt'):
        process(char)
pambda
quelle
0
#reading out the file at once in a list and then printing one-by-one
f=open('file.txt')
for i in list(f.read()):
    print(i)
ParagAb
quelle
Dies könnte zwar die Frage des Autors beantworten, es fehlen jedoch einige erklärende Wörter und Links zur Dokumentation. Rohcode-Schnipsel sind ohne einige Ausdrücke nicht sehr hilfreich. Möglicherweise ist es auch sehr hilfreich , eine gute Antwort zu schreiben . Bitte bearbeiten Sie Ihre Antwort.
Gelb
Sie brauchen die Besetzung nicht, um aufzulisten.
user240515