Python - Send file through JSON

6.7k Views Asked by At

I'm trying to create a live chat application using ws4py (if there are better socket libraries I would love recommendations) and I want to implement file transfer (specifically .wav files) in my application.

For text chat messages I'm currently using the JSON library to send a serialized dictionary over my sockets and decode them on either side. Something like this

message = raw_input("Message: ")
payload = {"username": self.username, "message": message}
payload["type"] = constants.CHAT
socket.send(json.dumps(payload), False)

I want to be able to do the same for file transfer so I can just have a JSON sent over where one of the fields is the data for the .wav file and the other fields would be things like username, fileName, fileExtension, ...

Is this the correct approach to sending a file? If it is, I can't seem to figure out how to get a file into a JSON string to send it over the wire. Here is what I am trying

fh = open('foo.wav', 'rb')
payload = {}
payload['content'] = fh.read()
import json
js = json.dumps(payload)

And this is the error I get

UnicodeDecodeError: 'utf8' codec can't decode bytes in position 4-5: invalid continuation byte

How would I go about serializing and deserializing a JSON containing a file so I can send it over a socket?

My goal is that once this works I can have the receiving end code for this transaction look like this

def received_message(self, received_message):
    payload = json.loads(received_message)
    filename = payload['filename']
    fileData = payload['content']
    fh = open(filename, 'wb')
    fh.write(fileData)
    fh.close()
1

There are 1 best solutions below

1
On BEST ANSWER

You need to make the binary blob into something that can be represented as a string (without random control characters, etc.). Typical approach there is to do some sort of encoding such as base64.

import base64
payload['content'] = base64.b64encode(fh.read())

That generates a hexadecimal string representation of the binary data.

Then on the other side:

fileData = base64.b64decode(payload['content'])