Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReadInt(), ReadByte(), ReadString(), etc. in Python?

Tags:

python

The functions ReadInt(), ReadByte(), and ReadString() (to name a few) exist in other languages for reading input from streams. I am trying to read from a socket, and I want to use functions like these. Are they tucked away in Python somewhere under a different way or has someone made a library for it?

Also, there are Writedatatype() counterparts.

like image 851
ryeguy Avatar asked Jan 14 '09 07:01

ryeguy


3 Answers

Python's way is using struct.unpack to read binary data. I'm very used to the BinaryReader and BinaryWriter in C#, so I made this:

from struct import *

class BinaryStream:
    def __init__(self, base_stream):
        self.base_stream = base_stream

    def readByte(self):
        return self.base_stream.read(1)

    def readBytes(self, length):
        return self.base_stream.read(length)

    def readChar(self):
        return self.unpack('b')

    def readUChar(self):
        return self.unpack('B')

    def readBool(self):
        return self.unpack('?')

    def readInt16(self):
        return self.unpack('h', 2)

    def readUInt16(self):
        return self.unpack('H', 2)

    def readInt32(self):
        return self.unpack('i', 4)

    def readUInt32(self):
        return self.unpack('I', 4)

    def readInt64(self):
        return self.unpack('q', 8)

    def readUInt64(self):
        return self.unpack('Q', 8)

    def readFloat(self):
        return self.unpack('f', 4)

    def readDouble(self):
        return self.unpack('d', 8)

    def readString(self):
        length = self.readUInt16()
        return self.unpack(str(length) + 's', length)

    def writeBytes(self, value):
        self.base_stream.write(value)

    def writeChar(self, value):
        self.pack('c', value)

    def writeUChar(self, value):
        self.pack('C', value)

    def writeBool(self, value):
        self.pack('?', value)

    def writeInt16(self, value):
        self.pack('h', value)

    def writeUInt16(self, value):
        self.pack('H', value)

    def writeInt32(self, value):
        self.pack('i', value)

    def writeUInt32(self, value):
        self.pack('I', value)

    def writeInt64(self, value):
        self.pack('q', value)

    def writeUInt64(self, value):
        self.pack('Q', value)

    def writeFloat(self, value):
        self.pack('f', value)

    def writeDouble(self, value):
        self.pack('d', value)

    def writeString(self, value):
        length = len(value)
        self.writeUInt16(length)
        self.pack(str(length) + 's', value)

    def pack(self, fmt, data):
        return self.writeBytes(pack(fmt, data))

    def unpack(self, fmt, length = 1):
        return unpack(fmt, self.readBytes(length))[0]

Once you have a stream, you put it in the BinaryStream constructor and you got a BinaryStream :)

Example:

from binary import BinaryStream

f = open("Users", "rb")
stream = BinaryStream(f)
users_count = stream.readUInt64()
for i in range(users_count):
    username = stream.readString()
    password = stream.readString()
like image 152
Zippo Avatar answered Nov 01 '22 19:11

Zippo


I think struct.unpack_from is what you're looking for.

like image 33
Swaroop C H Avatar answered Nov 01 '22 18:11

Swaroop C H


I used the code of Zippoxer and it works well for almost everything, thank you.

However I had some issue with readString(). It was specified in the C# doc that the length is encoded on 7 bytes. Thus I used readUChar instead of readUInt16:

def readString(self):
    length = self.readUChar()
    return self.unpack(str(length) + 's', length)

and it works now. Maybe it is specific to my problem ? But it may help someone...

like image 1
Thierry G. Avatar answered Nov 01 '22 20:11

Thierry G.