Python - 拆分文件
Python - split files
我目前有一个通过 requests.post() 请求文件的脚本。服务器在同一流中向我发送两个文件。我现在处理这个的方法是将它全部保存为一个文件,再次打开它,根据正则表达式字符串拆分文件,将其保存为一个新文件,然后删除旧文件。该文件足够大,我必须在 requests.post() 语句中设置 stream=True 并将其分块写入。
我希望有人知道更好的方法来发出 post 或处理返回的数据,以便第一次正确存储文件?或者这是最好的方法吗?
----添加当前代码----
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')
好吧,我很无聊,想找出最好的方法来做到这一点。事实证明,我在上面的评论中最初的方式过于复杂(除非考虑一些时间绝对关键或内存严重受限的情况)。缓冲区是实现此目的的一种更简单的方法,只要您一次使用 两个或更多块。此代码模拟问题场景以进行演示。
注意:根据正则表达式引擎的实现,这更有效并且需要 显着减少 str/byte 转换,因为使用正则表达式需要将每个字节块转换为字符串.下面的方法不需要字符串转换,而是仅对从 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 所指的 "chunks" 实际上是分发字节的方式,它已经拥有了所有字节。您可以使用 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')
我目前有一个通过 requests.post() 请求文件的脚本。服务器在同一流中向我发送两个文件。我现在处理这个的方法是将它全部保存为一个文件,再次打开它,根据正则表达式字符串拆分文件,将其保存为一个新文件,然后删除旧文件。该文件足够大,我必须在 requests.post() 语句中设置 stream=True 并将其分块写入。
我希望有人知道更好的方法来发出 post 或处理返回的数据,以便第一次正确存储文件?或者这是最好的方法吗?
----添加当前代码----
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')
好吧,我很无聊,想找出最好的方法来做到这一点。事实证明,我在上面的评论中最初的方式过于复杂(除非考虑一些时间绝对关键或内存严重受限的情况)。缓冲区是实现此目的的一种更简单的方法,只要您一次使用 两个或更多块。此代码模拟问题场景以进行演示。
注意:根据正则表达式引擎的实现,这更有效并且需要 显着减少 str/byte 转换,因为使用正则表达式需要将每个字节块转换为字符串.下面的方法不需要字符串转换,而是仅对从 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 所指的 "chunks" 实际上是分发字节的方式,它已经拥有了所有字节。您可以使用 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')