解密大文件时出现OpenSSL内存分配失败(NoMemoryError)求助
解决OpenSSL解密大文件时的内存分配错误(NoMemoryError)
嘿,这个坑我踩过!你遇到的问题根源很明确:你一次性把整个0.97GB的文件读进内存了。小文件这么玩没问题,但大文件直接用io.read会把所有内容塞进RAM,内存扛不住就触发了OpenSSL的内存分配失败错误。
咱们直接上解决方案——把一次性读写改成分块处理,每次只读取一小段数据,解密后立即写入输出文件,全程不会把整个文件放在内存里。
修改后的解密代码
首先重构decrypt方法,让它支持分块处理输入和输出流:
def decrypt(input_io, output_io) aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") aes.decrypt aes.key = "cryptoKeyString" aes.iv = "ivString" # 分块大小可以根据你的内存情况调整,64KB是比较稳妥的选择 chunk_size = 64 * 1024 while chunk = input_io.read(chunk_size) output_io.write(aes.update(chunk)) end # 处理最后一块的收尾数据,这步不能忘! output_io.write(aes.final) end
然后更新解密的调用逻辑,用文件流而非一次性读取:
def do_decrypt(input_file_path, output_file_path) # 使用块式打开文件,自动处理关闭,避免资源泄漏 File.open(input_file_path, 'rb') do |input_io| File.open(output_file_path, 'wb') do |output_io| decrypt(input_io, output_io) end end end
顺便优化你的加密逻辑
既然大文件解密会出问题,加密时也大概率会有同样的内存问题,建议把加密代码也改成分块模式:
def encrypt(input_io, output_io) aes = OpenSSL::Cipher::Cipher.new("AES-256-CBC") aes.encrypt aes.key = "cryptoKeyString" # 重要提醒:不要硬编码IV!这里只是示例,实际要随机生成 aes.iv = SecureRandom.random_bytes(aes.iv_len) # 把随机生成的IV写入输出文件开头,解密时先读取这部分 output_io.write(aes.iv) chunk_size = 64 * 1024 while chunk = input_io.read(chunk_size) output_io.write(aes.update(chunk)) end output_io.write(aes.final) end def do_encrypt(file_path, output_file_path) File.open(file_path, 'rb') do |input_io| File.open(output_file_path, 'wb') do |output_io| encrypt(input_io, output_io) end end end
关键注意事项
- 分块大小可以灵活调整,比如128KB或1MB,只要不超过你的可用内存就行。
- 绝对不要硬编码IV!AES-CBC的IV必须是随机且唯一的,硬编码会严重削弱加密安全性。上面的加密示例里已经改成随机生成IV并写入密文开头,解密时需要先读取IV(长度是
aes.iv_len)再设置给Cipher。
内容的提问来源于stack exchange,提问作者Satishakumar Awati
相关产品推荐
相关产品推荐

