将blob保存到python中的文件

时间:2017-09-07 07:21:49

标签: javascript python

我正在尝试将通过ajax发送的blob保存为python中的文件。在Python: How do I convert from binary to base 64 and back?

之前经历过这个
class SaveBlob(APIView):
    def post(self, request):
        vid = open("file.webm", "wb")
        video_stream = request.FILES['blob'].read()
        video_stream = struct.pack(video_stream).encode('base64')
        # vid.write(video_stream.decode('base64'))
        vid.write(video_stream)
        vid.close()
        return Response()

结果为error: bad char in struct format

只使用此vid.write(video_stream.decode('base64')) 而不使用struct.pack会保存文件,但是当我打开视频时,导致无法确定流的类型。

ajax调用是这样的,但我觉得它看起来很好。

function call_ajax(request_type,request_url,request_data) {

    var data_vid = new FormData();
    console.log(request_url);
    data_vid.append('blob', request_data);
    console.log(request_data);

    var data= [];
    try{
        $.ajax({
            type: request_type,
            url: request_url,
            data:data_vid,
            cors:true,
            processData: false,
            contentType: false,
            async:false,
            beforeSend: function(xhr) {
                    xhr.setRequestHeader('X-CSRFToken',Cookies.get('csrftoken'))
             },

            success: function(response){
                data =response;
            }
        });
    }catch(error){
        console.log(error);
    }
    return data;
}

任何帮助都将不胜感激。欢迎任何有关任何缺陷或可能原因的建议。

3 个答案:

答案 0 :(得分:2)

您可以使用Python的base64库对SaveBlob类中的数据进行编码和解码:

import base64

video_stream = "hello"

with open('file.webm', 'wb') as f_vid:
    f_vid.write(base64.b64encode(video_stream))

with open('file.webm', 'rb') as f_vid:
    video_stream = base64.b64decode(f_vid.read())

print video_stream

退回原始video_stream

hello

对于这个简单示例,保存的文件将显示为:

aGVsbG8=

答案 1 :(得分:2)

struct.pack的第一个参数是format string,它指定结构的布局。您只传递要打包的字节,因此将其解释为无效格式:

>>> bs = b'\x01\x56\x56'
>>> struct.pack(bs)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
struct.error: bad char in struct format

构造有效的格式字符串可以解决这个问题(但请注意,您需要根据数据和平台构建格式字符串):

>> n = len(bs)    # 3
>>> fmt = '{:d}s'.format(n)    # '3s'
>>> struct.pack(fmt, bs)
b'\x01VV'

如果要将数据写入磁盘,则不太可能需要打包 * 或base64编码数据;只需将字节直接写入文件:

class SaveBlob(APIView):
    def post(self, request):
        with open("file.webm", "wb") as vid:
            video_stream = request.FILES['blob'].read()
            vid.write(video_stream)
            return Response()

您的视频播放器应该能够读取二进制文件并正确解释它。

当传输机制需要ascii编码数据时,Base64编码实际上是用于传输二进制数据,因此仅仅为了写入文件而应用此编码没有任何好处。如果您确实需要对数据进行base64编码,请使用python的base64软件包,正如Martin Evans在答案中所建议的那样..

* 如果数据在具有不同endianness的平台之间移动,则可能需要打包数据。

答案 2 :(得分:0)

其他解决方案很有用,它会将文件写入磁盘仍然会说错误的文件格式或由于缺少插件而无法播放文件。

这与JavaScript(我不太满意)有关,我想在FormData中拥有所有元数据。我不确定为什么会这样。曾经在某个地方搜索过,发现这个有用了。

很高兴知道上面出了什么问题。会接受解释这个的任何其他答案。

class SaveVideo(APIView):
    def post(self, request):
        filename = 'demo.mp4'
        with open(filename, 'wb+') as destination:
            for chunk in request.FILES['video-blob'].chunks():
                destination.write(chunk)
        return Response({"status":"ok"})

的Javascript

function xhr(url, data, callback) {
      var request = new XMLHttpRequest();
            request.onreadystatechange = function () {
                if (request.readyState == 4 && request.status == 200) {
                   callback(request.responseText);
                }
            };

    request.open('POST', url);
    request.setRequestHeader('X-CSRFToken',Cookies.get('csrftoken'))
    request.send(data);
    }

    var fileType = 'video'; 


    var fileName = 'ABCDEF.webm'; 

    var formData = new FormData();
    formData.append(fileType , fileName);
    formData.append(fileType + '-blob', blob);
    xhr(url,formData,callback_function);