Binair bestand lezen en elke byte doorlopen

Hoe lees ik in Python een binair bestand en loop ik over elke byte van dat bestand?


Antwoord 1, autoriteit 100%

Python 2.4 en eerder

f = open("myfile", "rb")
try:
    byte = f.read(1)
    while byte != "":
        # Do stuff with byte.
        byte = f.read(1)
finally:
    f.close()

Python 2,5-2,7

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte != "":
        # Do stuff with byte.
        byte = f.read(1)

Merk op dat de instructie with niet beschikbaar is in versies van Python onder 2.5. Om het in v 2.5 te gebruiken, moet je het importeren:

from __future__ import with_statement

In 2.6 is dit niet nodig.

Python 3

In Python 3 is het een beetje anders. We krijgen niet langer onbewerkte tekens uit de stream in byte-modus, maar byte-objecten, dus we moeten de voorwaarde wijzigen:

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte != b"":
        # Do stuff with byte.
        byte = f.read(1)

Of zoals Benhoyt zegt, sla de niet-gelijke over en profiteer van het feit dat b""resulteert in onwaar. Dit maakt de code compatibel tussen 2.6 en 3.x zonder enige wijzigingen. Het zou u ook behoeden voor het wijzigen van de voorwaarde als u van bytemodus naar tekst gaat of omgekeerd.

with open("myfile", "rb") as f:
    byte = f.read(1)
    while byte:
        # Do stuff with byte.
        byte = f.read(1)

python 3.8

Vanaf nu kan dankzij operator := bovenstaande code op een kortere manier worden geschreven.

with open("myfile", "rb") as f:
    while (byte := f.read(1)):
        # Do stuff with byte.

Antwoord 2, autoriteit 42%

Deze generator levert bytes op uit een bestand en leest het bestand in stukjes:

def bytes_from_file(filename, chunksize=8192):
    with open(filename, "rb") as f:
        while True:
            chunk = f.read(chunksize)
            if chunk:
                for b in chunk:
                    yield b
            else:
                break
# example:
for b in bytes_from_file('filename'):
    do_stuff_with(b)

Zie de Python-documentatie voor informatie over iteratorsen generatoren.


Antwoord 3, autoriteit 13%

Als het bestand niet te groot is, is het een probleem om het in het geheugen te bewaren:

with open("filename", "rb") as f:
    bytes_read = f.read()
for b in bytes_read:
    process_byte(b)

waar process_byte staat voor een bewerking die u wilt uitvoeren op de doorgegeven byte.

Als je een stuk tegelijk wilt verwerken:

with open("filename", "rb") as f:
    bytes_read = f.read(CHUNKSIZE)
    while bytes_read:
        for b in bytes_read:
            process_byte(b)
        bytes_read = f.read(CHUNKSIZE)

De with-instructie is beschikbaar in Python 2.5 en hoger.


Antwoord 4, autoriteit 9%

Als u een bestand wilt lezen, één byte per keer (waarbij u de buffering negeert), kunt u de twee-argument iter(callable, sentinel)ingebouwde functie:

with open(filename, 'rb') as file:
    for byte in iter(lambda: file.read(1), b''):
        # Do stuff with byte

Het roept file.read(1)aan totdat het niets b''teruggeeft (lege bytestring). Het geheugen groeit niet onbeperkt voor grote bestanden. Je zou buffering=0kunnen doorgeven aan open(), om de buffering uit te schakelen — het garandeert dat er slechts één byte wordt gelezen per iteratie (langzaam).

with-statement sluit het bestand automatisch – inclusief het geval dat de code eronder een uitzondering maakt.

Ondanks de standaard aanwezigheid van interne buffering, is het nog steeds inefficiënt om één byte tegelijk te verwerken. Hier is bijvoorbeeld het hulpprogramma blackhole.pydat alles opeet wat het krijgt:

#!/usr/bin/env python3
"""Discard all input. `cat > /dev/null` analog."""
import sys
from functools import partial
from collections import deque
chunksize = int(sys.argv[1]) if len(sys.argv) > 1 else (1 << 15)
deque(iter(partial(sys.stdin.detach().read, chunksize), b''), maxlen=0)

Voorbeeld:

$ dd if=/dev/zero bs=1M count=1000 | python3 blackhole.py

Het verwerkt ~1,5 GB/swanneer chunksize == 32768op mijn computer en slechts ~7,5 MB/swanneer chunksize == 1. Dat wil zeggen, het is 200 keer langzamer om één byte per keer te lezen. Houd er rekening mee als u uw verwerking kunt herschrijven om meer dan één byte tegelijk te gebruiken en alsu prestaties nodig hebt.

Met

mmapkunt u een bestand behandelen als een bytearrayen een bestandsobject tegelijk . Het kan dienen als een alternatief voor het laden van het hele bestand in het geheugen als u toegang tot beide interfaces nodig hebt. In het bijzonder kunt u één byte tegelijk herhalen over een aan het geheugen toegewezen bestand door gewoon een gewone for-loop:

te gebruiken

from mmap import ACCESS_READ, mmap
with open(filename, 'rb', 0) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
    for byte in s: # length is equal to the current file size
        # Do stuff with byte

mmapondersteunt de plaknotatie. Bijvoorbeeld, mm[i:i+len]retourneert lenbytes uit het bestand dat begint op positie i. Het contextmanager-protocol wordt niet ondersteund vóór Python 3.2; je moet in dit geval expliciet mm.close()aanroepen. Elke byte doorlopen met behulp van mmapverbruikt meer geheugen dan file.read(1), maar mmapis een orde van grootte sneller.


Antwoord 5, autoriteit 7%

Binair bestand lezen in Python en elke byte doorlopen

Nieuw in Python 3.5 is de module pathlib, die een handige methode heeft om een bestand als bytes in te lezen, waardoor we de bytes kunnen herhalen. Ik beschouw dit als een fatsoenlijk (als snel en vies) antwoord:

import pathlib
for byte in pathlib.Path(path).read_bytes():
    print(byte)

Interessant dat dit het enige antwoord is om pathlibte noemen.

In Python 2 zou je dit waarschijnlijk doen (zoals Vinay Sajip ook suggereert):

with open(path, 'b') as file:
    for byte in file.read():
        print(byte)

In het geval dat het bestand te groot is om in het geheugen te herhalen, zou je het, idiomatisch, in stukjes kunnen opdelen met behulp van de functie itermet de callable, sentinelhandtekening – de Python 2-versie:

with open(path, 'b') as file:
    callable = lambda: file.read(1024)
    sentinel = bytes() # or b''
    for chunk in iter(callable, sentinel): 
        for byte in chunk:
            print(byte)

(Verschillende andere antwoorden vermelden dit, maar weinigen bieden een redelijke leesgrootte.)

Beste werkwijze voor grote bestanden of gebufferd/interactief lezen

Laten we een functie maken om dit te doen, inclusief idiomatisch gebruik van de standaardbibliotheek voor Python 3.5+:

from pathlib import Path
from functools import partial
from io import DEFAULT_BUFFER_SIZE
def file_byte_iterator(path):
    """given a path, return an iterator over the file
    that lazily loads the file
    """
    path = Path(path)
    with path.open('rb') as file:
        reader = partial(file.read1, DEFAULT_BUFFER_SIZE)
        file_iterator = iter(reader, bytes())
        for chunk in file_iterator:
            yield from chunk

Houd er rekening mee dat we file.read1gebruiken. file.readblokkeert totdat het alle gevraagde bytes of EOFkrijgt. file.read1stelt ons in staat om blokkering te voorkomen en kan hierdoor sneller terugkeren. Geen andere antwoorden vermelden dit ook.

Demonstratie van het gebruik van best practices:

Laten we een bestand maken met een megabyte (eigenlijk mebibyte) aan pseudowillekeurige gegevens:

import random
import pathlib
path = 'pseudorandom_bytes'
pathobj = pathlib.Path(path)
pathobj.write_bytes(
  bytes(random.randint(0, 255) for _ in range(2**20)))

Laten we het nu herhalen en in het geheugen materialiseren:

>>> l = list(file_byte_iterator(path))
>>> len(l)
1048576

We kunnen elk deel van de gegevens inspecteren, bijvoorbeeld de laatste 100 en de eerste 100 bytes:

>>> l[-100:]
[208, 5, 156, 186, 58, 107, 24, 12, 75, 15, 1, 252, 216, 183, 235, 6, 136, 50, 222, 218, 7, 65, 234, 129, 240, 195, 165, 215, 245, 201, 222, 95, 87, 71, 232, 235, 36, 224, 190, 185, 12, 40, 131, 54, 79, 93, 210, 6, 154, 184, 82, 222, 80, 141, 117, 110, 254, 82, 29, 166, 91, 42, 232, 72, 231, 235, 33, 180, 238, 29, 61, 250, 38, 86, 120, 38, 49, 141, 17, 190, 191, 107, 95, 223, 222, 162, 116, 153, 232, 85, 100, 97, 41, 61, 219, 233, 237, 55, 246, 181]
>>> l[:100]
[28, 172, 79, 126, 36, 99, 103, 191, 146, 225, 24, 48, 113, 187, 48, 185, 31, 142, 216, 187, 27, 146, 215, 61, 111, 218, 171, 4, 160, 250, 110, 51, 128, 106, 3, 10, 116, 123, 128, 31, 73, 152, 58, 49, 184, 223, 17, 176, 166, 195, 6, 35, 206, 206, 39, 231, 89, 249, 21, 112, 168, 4, 88, 169, 215, 132, 255, 168, 129, 127, 60, 252, 244, 160, 80, 155, 246, 147, 234, 227, 157, 137, 101, 84, 115, 103, 77, 44, 84, 134, 140, 77, 224, 176, 242, 254, 171, 115, 193, 29]

Itereer niet op regels voor binaire bestanden

Doe niet het volgende – dit trekt een stuk van willekeurige grootte totdat het bij een teken van een nieuwe regel komt – te langzaam als de stukken te klein zijn, en mogelijk ook te groot:

   with open(path, 'rb') as file:
        for chunk in file: # text newline iteration - not for bytes
            yield from chunk

Het bovenstaande is alleen goed voor wat semantisch door mensen leesbare tekstbestanden zijn (zoals platte tekst, code, markup, markdown etc… in wezen alles wat ascii, utf, latin, etc… gecodeerd is) die je zou moeten openen zonder de 'b'vlag.


Antwoord 6, autoriteit 4%

Om alle briljante punten van chrispy, Skurmedel, Ben Hoyt en Peter Hansen samen te vatten, zou dit de optimale oplossing zijn om een binair bestand byte voor byte te verwerken:

with open("myfile", "rb") as f:
    while True:
        byte = f.read(1)
        if not byte:
            break
        do_stuff_with(ord(byte))

Voor Python-versies 2.6 en hoger, omdat:

  • python buffers intern – geen noodzaak om chunks te lezen
  • DRY-principe – herhaal de leesregel niet
  • met statement zorgt voor een schoon bestand sluiten
  • ‘byte’ evalueert onwaar als er geen bytes meer zijn (niet als een byte nul is)

Of gebruik de oplossing van J.F. Sebastian voor verbeterde snelheid

from functools import partial
with open(filename, 'rb') as file:
    for byte in iter(partial(file.read, 1), b''):
        # Do stuff with byte

Of als je het als een generatorfunctie wilt, zoals gedemonstreerd door codeape:

def bytes_from_file(filename):
    with open(filename, "rb") as f:
        while True:
            byte = f.read(1)
            if not byte:
                break
            yield(ord(byte))
# example:
for b in bytes_from_file('filename'):
    do_stuff_with(b)

Antwoord 7, autoriteit 2%

Dit bericht zelf is geen direct antwoord op de vraag. Wat het in plaats daarvan is, is een gegevensgestuurde uitbreidbare benchmark die kan worden gebruikt om veel van de antwoorden (en variaties van het gebruik van nieuwe functies die zijn toegevoegd in latere, modernere versies van Python) die op deze vraag zijn gepost te vergelijken – en zou daarom behulpzaam zijn bij het bepalen welke de beste prestaties levert.

In enkele gevallen heb ik de code in het antwoord waarnaar wordt verwezen, aangepast om deze compatibel te maken met het benchmarkframework.

Ten eerste zijn hier de resultaten voor wat momenteel de nieuwste versies zijn van Python 2 & 3:

Fastest to slowest execution speeds with 32-bit Python 2.7.16
  numpy version 1.16.5
  Test file size: 1,024 KiB
  100 executions, best of 3 repetitions
1                  Tcll (array.array) :   3.8943 secs, rel speed   1.00x,   0.00% slower (262.95 KiB/sec)
2  Vinay Sajip (read all into memory) :   4.1164 secs, rel speed   1.06x,   5.71% slower (248.76 KiB/sec)
3            codeape + iter + partial :   4.1616 secs, rel speed   1.07x,   6.87% slower (246.06 KiB/sec)
4                             codeape :   4.1889 secs, rel speed   1.08x,   7.57% slower (244.46 KiB/sec)
5               Vinay Sajip (chunked) :   4.1977 secs, rel speed   1.08x,   7.79% slower (243.94 KiB/sec)
6           Aaron Hall (Py 2 version) :   4.2417 secs, rel speed   1.09x,   8.92% slower (241.41 KiB/sec)
7                     gerrit (struct) :   4.2561 secs, rel speed   1.09x,   9.29% slower (240.59 KiB/sec)
8                     Rick M. (numpy) :   8.1398 secs, rel speed   2.09x, 109.02% slower (125.80 KiB/sec)
9                           Skurmedel :  31.3264 secs, rel speed   8.04x, 704.42% slower ( 32.69 KiB/sec)
Benchmark runtime (min:sec) - 03:26

Fastest to slowest execution speeds with 32-bit Python 3.8.0
  numpy version 1.17.4
  Test file size: 1,024 KiB
  100 executions, best of 3 repetitions
1  Vinay Sajip + "yield from" + "walrus operator" :   3.5235 secs, rel speed   1.00x,   0.00% slower (290.62 KiB/sec)
2                       Aaron Hall + "yield from" :   3.5284 secs, rel speed   1.00x,   0.14% slower (290.22 KiB/sec)
3         codeape + iter + partial + "yield from" :   3.5303 secs, rel speed   1.00x,   0.19% slower (290.06 KiB/sec)
4                      Vinay Sajip + "yield from" :   3.5312 secs, rel speed   1.00x,   0.22% slower (289.99 KiB/sec)
5      codeape + "yield from" + "walrus operator" :   3.5370 secs, rel speed   1.00x,   0.38% slower (289.51 KiB/sec)
6                          codeape + "yield from" :   3.5390 secs, rel speed   1.00x,   0.44% slower (289.35 KiB/sec)
7                                      jfs (mmap) :   4.0612 secs, rel speed   1.15x,  15.26% slower (252.14 KiB/sec)
8              Vinay Sajip (read all into memory) :   4.5948 secs, rel speed   1.30x,  30.40% slower (222.86 KiB/sec)
9                        codeape + iter + partial :   4.5994 secs, rel speed   1.31x,  30.54% slower (222.64 KiB/sec)
10                                        codeape :   4.5995 secs, rel speed   1.31x,  30.54% slower (222.63 KiB/sec)
11                          Vinay Sajip (chunked) :   4.6110 secs, rel speed   1.31x,  30.87% slower (222.08 KiB/sec)
12                      Aaron Hall (Py 2 version) :   4.6292 secs, rel speed   1.31x,  31.38% slower (221.20 KiB/sec)
13                             Tcll (array.array) :   4.8627 secs, rel speed   1.38x,  38.01% slower (210.58 KiB/sec)
14                                gerrit (struct) :   5.0816 secs, rel speed   1.44x,  44.22% slower (201.51 KiB/sec)
15                 Rick M. (numpy) + "yield from" :  11.8084 secs, rel speed   3.35x, 235.13% slower ( 86.72 KiB/sec)
16                                      Skurmedel :  11.8806 secs, rel speed   3.37x, 237.18% slower ( 86.19 KiB/sec)
17                                Rick M. (numpy) :  13.3860 secs, rel speed   3.80x, 279.91% slower ( 76.50 KiB/sec)
Benchmark runtime (min:sec) - 04:47

Ik heb het ook uitgevoerd met een veel groter 10 MiB-testbestand (dat bijna een uur in beslag nam) en kreeg prestatieresultaten die vergelijkbaar waren met de hierboven getoonde.

Hier is de code die is gebruikt om de benchmarking uit te voeren:

from __future__ import print_function
import array
import atexit
from collections import deque, namedtuple
import io
from mmap import ACCESS_READ, mmap
import numpy as np
from operator import attrgetter
import os
import random
import struct
import sys
import tempfile
from textwrap import dedent
import time
import timeit
import traceback
try:
    xrange
except NameError:  # Python 3
    xrange = range
class KiB(int):
    """ KibiBytes - multiples of the byte units for quantities of information. """
    def __new__(self, value=0):
        return 1024*value
BIG_TEST_FILE = 1  # MiBs or 0 for a small file.
SML_TEST_FILE = KiB(64)
EXECUTIONS = 100  # Number of times each "algorithm" is executed per timing run.
TIMINGS = 3  # Number of timing runs.
CHUNK_SIZE = KiB(8)
if BIG_TEST_FILE:
    FILE_SIZE = KiB(1024) * BIG_TEST_FILE
else:
    FILE_SIZE = SML_TEST_FILE  # For quicker testing.
# Common setup for all algorithms -- prefixed to each algorithm's setup.
COMMON_SETUP = dedent("""
    # Make accessible in algorithms.
    from __main__ import array, deque, get_buffer_size, mmap, np, struct
    from __main__ import ACCESS_READ, CHUNK_SIZE, FILE_SIZE, TEMP_FILENAME
    from functools import partial
    try:
        xrange
    except NameError:  # Python 3
        xrange = range
""")
def get_buffer_size(path):
    """ Determine optimal buffer size for reading files. """
    st = os.stat(path)
    try:
        bufsize = st.st_blksize # Available on some Unix systems (like Linux)
    except AttributeError:
        bufsize = io.DEFAULT_BUFFER_SIZE
    return bufsize
# Utility primarily for use when embedding additional algorithms into benchmark.
VERIFY_NUM_READ = """
    # Verify generator reads correct number of bytes (assumes values are correct).
    bytes_read = sum(1 for _ in file_byte_iterator(TEMP_FILENAME))
    assert bytes_read == FILE_SIZE, \
           'Wrong number of bytes generated: got {:,} instead of {:,}'.format(
                bytes_read, FILE_SIZE)
"""
TIMING = namedtuple('TIMING', 'label, exec_time')
class Algorithm(namedtuple('CodeFragments', 'setup, test')):
    # Default timeit "stmt" code fragment.
    _TEST = """
        #for b in file_byte_iterator(TEMP_FILENAME):  # Loop over every byte.
        #    pass  # Do stuff with byte...
        deque(file_byte_iterator(TEMP_FILENAME), maxlen=0)  # Data sink.
    """
    # Must overload __new__ because (named)tuples are immutable.
    def __new__(cls, setup, test=None):
        """ Dedent (unindent) code fragment string arguments.
        Args:
          `setup` -- Code fragment that defines things used by `test` code.
                     In this case it should define a generator function named
                     `file_byte_iterator()` that will be passed that name of a test file
                     of binary data. This code is not timed.
          `test` -- Code fragment that uses things defined in `setup` code.
                    Defaults to _TEST. This is the code that's timed.
        """
        test =  cls._TEST if test is None else test  # Use default unless one is provided.
        # Uncomment to replace all performance tests with one that verifies the correct
        # number of bytes values are being generated by the file_byte_iterator function.
        #test = VERIFY_NUM_READ
        return tuple.__new__(cls, (dedent(setup), dedent(test)))
algorithms = {
    'Aaron Hall (Py 2 version)': Algorithm("""
        def file_byte_iterator(path):
            with open(path, "rb") as file:
                callable = partial(file.read, 1024)
                sentinel = bytes() # or b''
                for chunk in iter(callable, sentinel):
                    for byte in chunk:
                        yield byte
    """),
    "codeape": Algorithm("""
        def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
            with open(filename, "rb") as f:
                while True:
                    chunk = f.read(chunksize)
                    if chunk:
                        for b in chunk:
                            yield b
                    else:
                        break
    """),
    "codeape + iter + partial": Algorithm("""
        def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
            with open(filename, "rb") as f:
                for chunk in iter(partial(f.read, chunksize), b''):
                    for b in chunk:
                        yield b
    """),
    "gerrit (struct)": Algorithm("""
        def file_byte_iterator(filename):
            with open(filename, "rb") as f:
                fmt = '{}B'.format(FILE_SIZE)  # Reads entire file at once.
                for b in struct.unpack(fmt, f.read()):
                    yield b
    """),
    'Rick M. (numpy)': Algorithm("""
        def file_byte_iterator(filename):
            for byte in np.fromfile(filename, 'u1'):
                yield byte
    """),
    "Skurmedel": Algorithm("""
        def file_byte_iterator(filename):
            with open(filename, "rb") as f:
                byte = f.read(1)
                while byte:
                    yield byte
                    byte = f.read(1)
    """),
    "Tcll (array.array)": Algorithm("""
        def file_byte_iterator(filename):
            with open(filename, "rb") as f:
                arr = array.array('B')
                arr.fromfile(f, FILE_SIZE)  # Reads entire file at once.
                for b in arr:
                    yield b
    """),
    "Vinay Sajip (read all into memory)": Algorithm("""
        def file_byte_iterator(filename):
            with open(filename, "rb") as f:
                bytes_read = f.read()  # Reads entire file at once.
            for b in bytes_read:
                yield b
    """),
    "Vinay Sajip (chunked)": Algorithm("""
        def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
            with open(filename, "rb") as f:
                chunk = f.read(chunksize)
                while chunk:
                    for b in chunk:
                        yield b
                    chunk = f.read(chunksize)
    """),
}  # End algorithms
#
# Versions of algorithms that will only work in certain releases (or better) of Python.
#
if sys.version_info >= (3, 3):
    algorithms.update({
        'codeape + iter + partial + "yield from"': Algorithm("""
            def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
                with open(filename, "rb") as f:
                    for chunk in iter(partial(f.read, chunksize), b''):
                        yield from chunk
        """),
        'codeape + "yield from"': Algorithm("""
            def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
                with open(filename, "rb") as f:
                    while True:
                        chunk = f.read(chunksize)
                        if chunk:
                            yield from chunk
                        else:
                            break
        """),
        "jfs (mmap)": Algorithm("""
            def file_byte_iterator(filename):
                with open(filename, "rb") as f, \
                     mmap(f.fileno(), 0, access=ACCESS_READ) as s:
                    yield from s
        """),
        'Rick M. (numpy) + "yield from"': Algorithm("""
            def file_byte_iterator(filename):
            #    data = np.fromfile(filename, 'u1')
                yield from np.fromfile(filename, 'u1')
        """),
        'Vinay Sajip + "yield from"': Algorithm("""
            def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
                with open(filename, "rb") as f:
                    chunk = f.read(chunksize)
                    while chunk:
                        yield from chunk  # Added in Py 3.3
                        chunk = f.read(chunksize)
        """),
    })  # End Python 3.3 update.
if sys.version_info >= (3, 5):
    algorithms.update({
        'Aaron Hall + "yield from"': Algorithm("""
            from pathlib import Path
            def file_byte_iterator(path):
                ''' Given a path, return an iterator over the file
                    that lazily loads the file.
                '''
                path = Path(path)
                bufsize = get_buffer_size(path)
                with path.open('rb') as file:
                    reader = partial(file.read1, bufsize)
                    for chunk in iter(reader, bytes()):
                        yield from chunk
        """),
    })  # End Python 3.5 update.
if sys.version_info >= (3, 8, 0):
    algorithms.update({
        'Vinay Sajip + "yield from" + "walrus operator"': Algorithm("""
            def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
                with open(filename, "rb") as f:
                    while chunk := f.read(chunksize):
                        yield from chunk  # Added in Py 3.3
        """),
        'codeape + "yield from" + "walrus operator"': Algorithm("""
            def file_byte_iterator(filename, chunksize=CHUNK_SIZE):
                with open(filename, "rb") as f:
                    while chunk := f.read(chunksize):
                        yield from chunk
        """),
    })  # End Python 3.8.0 update.update.
#### Main ####
def main():
    global TEMP_FILENAME
    def cleanup():
        """ Clean up after testing is completed. """
        try:
            os.remove(TEMP_FILENAME)  # Delete the temporary file.
        except Exception:
            pass
    atexit.register(cleanup)
    # Create a named temporary binary file of pseudo-random bytes for testing.
    fd, TEMP_FILENAME = tempfile.mkstemp('.bin')
    with os.fdopen(fd, 'wb') as file:
         os.write(fd, bytearray(random.randrange(256) for _ in range(FILE_SIZE)))
    # Execute and time each algorithm, gather results.
    start_time = time.time()  # To determine how long testing itself takes.
    timings = []
    for label in algorithms:
        try:
            timing = TIMING(label,
                            min(timeit.repeat(algorithms[label].test,
                                              setup=COMMON_SETUP + algorithms[label].setup,
                                              repeat=TIMINGS, number=EXECUTIONS)))
        except Exception as exc:
            print('{} occurred timing the algorithm: "{}"\n  {}'.format(
                    type(exc).__name__, label, exc))
            traceback.print_exc(file=sys.stdout)  # Redirect to stdout.
            sys.exit(1)
        timings.append(timing)
    # Report results.
    print('Fastest to slowest execution speeds with {}-bit Python {}.{}.{}'.format(
            64 if sys.maxsize > 2**32 else 32, *sys.version_info[:3]))
    print('  numpy version {}'.format(np.version.full_version))
    print('  Test file size: {:,} KiB'.format(FILE_SIZE // KiB(1)))
    print('  {:,d} executions, best of {:d} repetitions'.format(EXECUTIONS, TIMINGS))
    print()
    longest = max(len(timing.label) for timing in timings)  # Len of longest identifier.
    ranked = sorted(timings, key=attrgetter('exec_time')) # Sort so fastest is first.
    fastest = ranked[0].exec_time
    for rank, timing in enumerate(ranked, 1):
        print('{:<2d} {:>{width}} : {:8.4f} secs, rel speed {:6.2f}x, {:6.2f}% slower '
              '({:6.2f} KiB/sec)'.format(
                    rank,
                    timing.label, timing.exec_time, round(timing.exec_time/fastest, 2),
                    round((timing.exec_time/fastest - 1) * 100, 2),
                    (FILE_SIZE/timing.exec_time) / KiB(1),  # per sec.
                    width=longest))
    print()
    mins, secs = divmod(time.time()-start_time, 60)
    print('Benchmark runtime (min:sec) - {:02d}:{:02d}'.format(int(mins),
                                                               int(round(secs))))
main()

Antwoord 8

Python 3, lees het hele bestand tegelijk:

with open("filename", "rb") as binary_file:
    # Read the whole file at once
    data = binary_file.read()
    print(data)

Je kunt herhalen wat je wilt met de variabele data.


Antwoord 9

Na al het bovenstaande te hebben geprobeerd en het antwoord van @Aaron Hall te hebben gebruikt, kreeg ik geheugenfouten voor een bestand van ~90 Mb op een computer met Windows 10, 8 Gb RAM en Python 3.5 32-bit. Ik werd door een collega aanbevolen om in plaats daarvan numpyte gebruiken en het doet wonderen.

Verreweg de snelste om een volledig binair bestand te lezen (dat ik heb getest) is:

import numpy as np
file = "binary_file.bin"
data = np.fromfile(file, 'u1')

Referentie

Meerdere malen sneller dan alle andere methoden tot nu toe. Ik hoop dat het iemand helpt!


Antwoord 10

Als u veel binaire gegevens moet lezen, kunt u de struct overwegen module. Het is gedocumenteerd als het converteren van “tussen C- en Python-typen”, maar natuurlijk zijn bytes bytes, en of die als C-typen zijn gemaakt, doet er niet toe. Als uw binaire gegevens bijvoorbeeld twee gehele getallen van 2 bytes en één geheel getal van 4 bytes bevatten, kunt u deze als volgt lezen (voorbeeld overgenomen uit de documentatie van struct):

>>> struct.unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)

Misschien vindt u dit handiger, sneller of beide, dan expliciet de inhoud van een bestand te herhalen.


Antwoord 11

Als je op zoek bent naar iets snels, hier is een methode die ik gebruik en die al jaren werkt:

from array import array
with open( path, 'rb' ) as file:
    data = array( 'B', file.read() ) # buffer the file
# evaluate it's data
for byte in data:
    v = byte # int value
    c = chr(byte)

als u chars wilt herhalen in plaats van ints, kunt u eenvoudig data = file.read()gebruiken, wat een bytes()-object in py3 zou moeten zijn.


Antwoord 12

voor groot formaat denk ik dat het gebruik van een generator niet slecht zal zijn, dit antwoord is om zoiets als een bestand te lezen, hoewel @codeapp een soortgelijk antwoord heeft, denk ik dat het logischer is om de binnenste lus te verwijderen.

def read_chunk(file_object, chunk_size=125):
    while True:
        file =  file_object.read(chunk_size)
        if not file:
            break
        yield file
#sample use 
buffer = io.BytesIO()
file = open('myfile', 'r')
for chunk in read_chunk(file):
    buffer.write(chunk)
buffer.seek(0)
// save the file or do whatever you want here

je kunt het nog steeds gebruiken als een normale lijst, ik denk niet dat dit van enig nut is, maar

file_list = list(read_chunk(file, chunk_size=10000))
for i in file_list:
    # do something

en krijg ook de index van elk stuk

for index, chunk in enumurate(read_chunk(file, chunk_size=10000)):
    #use the index as a number index
    # you can try and get the size of each chunk with this 
    length = len(chunk)

let op, betalen let op de grootte van het bestand, en de chunk_size is altijd in bytes bij opmerking.


Antwoord 13

Hier is een voorbeeld van het lezen van Network endian-gegevens met behulp van Numpy fromfile-adressering van @Nirmal-opmerkingen hierboven:

dtheader= np.dtype([('Start Name','b', (4,)),
                ('Message Type', np.int32, (1,)),
                ('Instance', np.int32, (1,)),
                ('NumItems', np.int32, (1,)),
                ('Length', np.int32, (1,)),
                ('ComplexArray', np.int32, (1,))])
dtheader=dtheader.newbyteorder('>')
headerinfo = np.fromfile(iqfile, dtype=dtheader, count=1)
print(raw['Start Name'])

Ik hoop dat dit helpt. Het probleem is dat fromfile EOF niet herkent en toelaat om op een elegante manier uit de lus te breken voor bestanden van willekeurige grootte.

Other episodes