2

我目前有一个通过requests.post() 请求文件的脚本。服务器在同一个流中向我发送两个文件。我现在处理的方式是将其全部保存为一个文件,再次打开它,根据正则表达式字符串拆分文件,将其保存为新文件,然后删除旧文件。该文件足够大,我必须在我的 requests.post() 语句中使用 stream=True 并将其写入块中。

我希望也许有人知道更好的方法来发布帖子或处理返回的数据,以便第一次正确存储文件?或者这是最好的方法吗?

----添加当前代码----

if not os.path.exists(output_path):
    os.makedirs(output_path)

memFile = requests.post(url, data=etree.tostring(etXML), headers=headers, stream=True)

outFile = open('output/tempfile', 'wb')

for chunk in memFile.iter_content(chunk_size=512):
    if chunk:
        outFile.write(chunk)

f = open('output/tempfile', 'rb').read().split('\r\n\r\n')

arf = open('output/recording.arf', 'wb')
arf.write(f[3])
os.remove('output/tempfile')
4

1 回答 1

1

好吧,我很无聊,想找出最好的方法来做到这一点。事实证明,我在上面的评论中最初的方式过于复杂(除非考虑到时间绝对关键或内存受到严重限制的某些场景)。缓冲区是实现此目的的一种更简单的方法,只要您一次占用两个或更多块。此代码模拟问题场景以进行演示。

注意:根据正则表达式引擎的实现,这更有效并且需要的字符串/字节转换显着减少,因为使用正则表达式需要将每个字节块转换为字符串。下面的方法不需要字符串转换,而是仅对从返回的字节进行操作request.post(),然后将这些相同的字节写入文件,而不进行转换。

from pprint import pprint

someString = '''I currently have a script that requests a file via a requests.post(). The server sends me two files in the same stream. The way I am processing this right now is to save it all as one file, open it again, split the file based on a regex string, save it as a new file, and delete the old one. The file is large enough that I have to stream=True in my requests.post() statement and write it in chunks.

I was hoping that maybe someone knows a better way to issue the post or work with the data coming back so that the files are stored correctly the first time? Or is this the best way to do it?'''

n = 16
# emulate a stream by creating 37 blocks of 16 bytes
byteBlocks = [bytearray(someString[i:i+n]) for i in range(0, len(someString), n)]
pprint(byteBlocks)

# this string is present twice, but both times it is split across two bytearrays
matchBytes = bytearray('requests.post()')

# our buffer
buff = bytearray()

count = 0
for bb in byteBlocks:
    buff += bb
    count += 1

    # every two blocks
    if (count % 2) == 0:

        if count == 2:
            start = 0
        else:
            start = len(matchBytes)

        # check the bytes starting from block (n -2 -len(matchBytes)) to (len(buff) -len(matchBytes))
        # this will check all the bytes only once...
        if matchBytes in buff[ ((count-2)*n)-start : len(buff)-len(matchBytes) ]:
            print('Match starting at index:', buff.index(matchBytes), 'ending at:', buff.index(matchBytes)+len(matchBytes))

更新:

因此,鉴于更新的问题,此代码可能无需创建临时文件。我无法准确测试它,因为我没有类似的响应,但您应该能够自己找出任何错误。

由于您实际上并没有直接使用流,即您从 requests.post() 中获得了完成的响应对象,因此您不必担心在网络意义上使用块。requests所指的“块”实际上是分发字节的方式,它已经拥有了所有字节。您可以使用直接访问字节,r.raw.read(n)但据我所知,请求对象不允许您查看“r.raw”中有多少字节,因此您或多或少被迫使用“iter_content” “ 方法。

无论如何,这段代码应该将请求对象中的所有字节复制到一个字符串中,然后您可以像以前一样搜索和拆分该字符串。

memFile = requests.post(url, data=etree.tostring(etXML), headers=headers, stream=True)

match = '\r\n\r\n'
data = ''

for chunk in memFile.iter_content(chunk_size=512):
    if chunk:
        data += chunk

f = data.split(match)

arf = open('output/recording.arf', 'wb')
arf.write(f[3])
os.remove('output/tempfile')
于 2017-07-31T21:06:32.403 回答