在审核了SO Ruby: Split binary data后,我使用了以下代码。
zh
然而,它很慢:
z = 'A' * 1_000_000
z.bytes.each_slice( STREAMING_CHUNK_SIZE ).each do | chunk |
c = chunk.pack( 'C*' )
end
98ms来切片并打包1MB文件。这很慢。
使用案例
服务器从外部API接收二进制数据,并使用Benchmark.realtime do
...
=> 0.0983949700021185
对其进行流式传输
数据预计在50KB到5MB之间,平均为500KB。
那么,如何在Ruby中有效地分割二进制数据?
答案 0 :(得分:5)
您的代码看起来不错,使用正确的Ruby方法和正确的语法,但它仍然是:
以下代码直接从字符串中提取部分,而不进行任何转换:
def get_binary_chunks(string, size)
Array.new(((string.length + size - 1) / size)) { |i| string.byteslice(i * size, size) }
end
(string.length + size - 1) / size)
只是为了避免错过最后一个块,如果它小于size
。
使用500kB的pdf文件和12345字节的块,Fruity返回:
Running each test 16 times. Test will take about 28 seconds.
_eric_duminil is faster than _b_seven by 380x ± 100.0
get_binary_chunks
在此示例中也比StringIO#each(n)
快6倍。
如果你确定字符串是二进制的(不是带有'ä'等多字节字符的UTF8),你可以使用slice
而不是byteslice
:
def get_binary_chunks(string, size)
Array.new(((string.length + size - 1) / size)) { |i| string.slice(i * size, size) }
end
使代码更快(与您的方法相比约为500倍)。
如果您将此代码与Unicode字符串一起使用,则这些字符块将包含size
个字符,但字节可能超过size
。
最后,如果您对获取字符串数组不感兴趣,可以直接使用这些块:
def send_binary_chunks(socket, string, size)
((string.length + size - 1) / size).times do |i|
socket.write string.slice(i * size, size)
end
end
答案 1 :(得分:3)
将StringIO#each(n)
与包含BINARY
编码的字符串一起使用
require 'stringio'
string.force_encoding(Encoding::BINARY)
StringIO.new(string).each(size) { |chunk| socket.write(chunk) }
这只是在将中间数组推送到套接字之前分配它们。