更新加密JSON遇MemoryStream不可扩展异常及代码调整求助
异常原因分析及代码合理性确认
一、"Memory stream is not expandable"异常原因
最初的代码触发异常的核心原因有两点:
- MemoryStream不可扩展:用固定长度
byte[]初始化的MemoryStream,底层依赖静态数组,不支持动态扩容。而CryptoStream在Write模式下加密数据时,需要向流写入内容并可能扩展流容量,因此直接抛出NotSupportedException。 - 逻辑错误:原代码将序列化后的JSON转成字节数组存入
MemoryStream,又试图通过CryptoStream往同一个只读内存流写入数据,完全不符合加密逻辑——加密应该是将明文数据传入加密流,最终输出到可写的目标载体(如文件),而非往固定长度的内存流写数据。
二、调整后代码的合理性确认
调整后的代码改用File.Create()创建可写的FileStream作为CryptoStream的底层流,解决了原异常的根本问题,整体逻辑方向正确,但仍有几个细节需要优化:
1. 编码一致性问题
当前代码用Encoding.ASCII.GetBytes(newContent)转换JSON字符串,ASCII编码无法处理非ASCII字符(如中文、特殊符号),会导致数据丢失。应改为和序列化逻辑一致的Encoding.UTF8:
cryptoStream.Write(Encoding.UTF8.GetBytes(newContent));
2. 确保加密数据完全写入
CryptoStream内部有缓冲区,仅依赖using块自动释放可能无法保证所有加密数据都写入文件。建议在Write后显式调用FlushFinalBlock(),强制清空缓冲区:
cryptoStream.Write(Encoding.UTF8.GetBytes(newContent)); cryptoStream.FlushFinalBlock();
3. 显式配置AES参数
AES的默认模式(CBC)和填充方式(PKCS7)虽然通用,但显式指定能避免不同环境下的默认值差异,提升代码兼容性:
using Aes aesProvider = Aes.Create(); aesProvider.Key = Convert.FromBase64String(Key); aesProvider.IV = Convert.FromBase64String(IV); aesProvider.Mode = CipherMode.CBC; // 显式指定加密模式 aesProvider.Padding = PaddingMode.PKCS7; // 显式指定填充方式
4. 异常处理补充
实际场景中,文件操作(如权限不足、路径无效)和加密操作(如Key/IV长度不合法)都可能抛出异常,建议添加必要的异常捕获逻辑,避免程序直接崩溃。
优化后的完整代码示例
public void SetLevelData(GameLevel value) { var newContent = JsonConvert.SerializeObject(value); using FileStream stream = File.Create(GetJSONPath()); using Aes aesProvider = Aes.Create(); aesProvider.Key = Convert.FromBase64String(Key); aesProvider.IV = Convert.FromBase64String(IV); aesProvider.Mode = CipherMode.CBC; aesProvider.Padding = PaddingMode.PKCS7; using ICryptoTransform cryptoTransform = aesProvider.CreateEncryptor(); using CryptoStream cryptoStream = new CryptoStream(stream, cryptoTransform, CryptoStreamMode.Write); byte[] plainBytes = Encoding.UTF8.GetBytes(newContent); cryptoStream.Write(plainBytes, 0, plainBytes.Length); cryptoStream.FlushFinalBlock(); }
内容的提问来源于stack exchange,提问作者Newboy11
相关产品推荐
相关产品推荐

