如何将整数转为固定长度字节数组以减少大文件写入的字符串分配?
优化多GB级固定长度文件写入,减少字符串分配
问题背景
需要写入多GB级别的固定长度文件,当前用StreamWriter配合字符串插值的实现会产生大量字符串分配,影响性能。目标是改用FileStream.Write(byte[])直接写入字节数组,彻底避免不必要的内存开销。
当前实现代码:
using (var streamWriter = new StreamWriter(fileName)) { for (int i = 0; i < rowsCount; i++) { foreach (var cellInfo in cellInfos) streamWriter.Write($"{cellInfo.Info1[i],-10}{cellInfo.Info2[i],-10}"); streamWriter.WriteLine(); } }
最终需要生成的固定长度文件示例(每个数字左对齐,不足10位补空格):
114001 2979993 1 2238001 324585 2985606 2980884 2532097 2532097 2980884 1 2985606 1 2985606 1492803 1 2791025 2485160 1492803 1 2106095 2720047 971452 2952105 1 2985606 1 2985606 324585 2985606 1195045 2985606 365001 2973993 1402746 1442502 223569 2738205 1121779 2744137 2744137 1121779 1990399 995210 1990399 995210 1759696 1944745 1598017 2485161 1703338 1195696 979974 2720052 251107 2975092 1990399 995210 1990399 995210 223569 2738205 1130022 995240
解决方案
核心逻辑是预分配每行的字节数组,将int直接转换为固定长度的字节段填充到数组中,全程避免字符串分配。
1. 基础实现(少量字符串分配)
先实现一个工具方法,把int转成左对齐、长度为10的字节数组:
private static void IntToFixedLengthBytes(int value, byte[] buffer, int startIndex, Encoding encoding) { string str = value.ToString(); byte[] strBytes = encoding.GetBytes(str); // 复制数字字节到目标数组 Buffer.BlockCopy(strBytes, 0, buffer, startIndex, strBytes.Length); // 剩余位置填充空格(ASCII空格字节值为32) int spaceCount = 10 - strBytes.Length; for (int i = 0; i < spaceCount; i++) { buffer[startIndex + strBytes.Length + i] = 32; } }
完整写入代码:
// 预计算每行字节长度:每个cellInfo输出2个10字节字段 int rowByteLength = cellInfos.Count * 2 * 10; byte[] rowBuffer = new byte[rowByteLength]; byte[] newLineBytes = Encoding.Default.GetBytes(Environment.NewLine); using (FileStream fs = File.Create(fileName)) { for (int i = 0; i < rowsCount; i++) { int currentIndex = 0; foreach (var cellInfo in cellInfos) { // 写入Info1[i] IntToFixedLengthBytes(cellInfo.Info1[i], rowBuffer, currentIndex, Encoding.Default); currentIndex += 10; // 写入Info2[i] IntToFixedLengthBytes(cellInfo.Info2[i], rowBuffer, currentIndex, Encoding.Default); currentIndex += 10; } // 写入整行数据 fs.Write(rowBuffer, 0, rowByteLength); // 写入换行符 fs.Write(newLineBytes, 0, newLineBytes.Length); } }
2. 极致优化(零字符串分配)
如果要彻底消除字符串分配,直接将int转换为ASCII字节,跳过字符串中间层:
private static void IntToFixedLengthBytesNoString(int value, byte[] buffer, int startIndex) { // 处理负数(无负数场景可省略) bool isNegative = value < 0; if (isNegative) value = -value; // 从后往前填充数字的ASCII字节 int pos = startIndex + 9; do { buffer[pos--] = (byte)('0' + (value % 10)); value /= 10; } while (value > 0 && pos >= startIndex); // 写入负号 if (isNegative && pos >= startIndex) buffer[pos--] = (byte)'-'; // 剩余位置填充空格 while (pos >= startIndex) buffer[pos--] = 32; }
使用时替换上述IntToFixedLengthBytes即可,适合超大规模数据写入场景。
内容的提问来源于stack exchange,提问作者Rand Random
相关产品推荐
相关产品推荐

