C# 随机排列真正巨大的文本文件行
我想随机化一个文件中有超过3200万行10位字符串的行。我知道如何使用C# 随机排列真正巨大的文本文件行,c#,performance,memory,file-io,C#,Performance,Memory,File Io,我想随机化一个文件中有超过3200万行10位字符串的行。我知道如何使用File.ReadAllLines(…).OrderBy(s=>random.Next()).ToArray(),但这不是内存效率,因为它会将所有内容加载到内存中(超过1.4GB),并且仅适用于x64体系结构 另一种方法是将其拆分并随机分配较短的文件,然后合并它们,但我想知道是否有更好的方法来做到这一点。您当前的方法将分配至少2个大字符串数组(可能更多——我不知道OrderBy是如何实现的,但它可能自己分配) 如果通过在行之间
File.ReadAllLines(…).OrderBy(s=>random.Next()).ToArray()
,但这不是内存效率,因为它会将所有内容加载到内存中(超过1.4GB),并且仅适用于x64体系结构
另一种方法是将其拆分并随机分配较短的文件,然后合并它们,但我想知道是否有更好的方法来做到这一点。您当前的方法将分配至少2个大字符串数组(可能更多——我不知道OrderBy是如何实现的,但它可能自己分配) 如果通过在行之间进行随机排列(例如使用),将数据“就地”随机化,将最大限度地减少内存使用。当然,如果文件很大,它仍然会很大,但是您不会分配超出需要的内存
编辑:如果所有行具有相同的长度(*),这意味着您可以对文件中的给定行进行随机访问,因此您可以直接在文件中执行Fisher-Yates洗牌
(*)并且假设您没有使用字符可以具有不同字节长度的编码,如UTF-8,此应用程序使用字节数组演示您想要的内容
公共类程序
{
私有静态随机=新随机();
公共静态void Main(字符串[]args)
{
//创建大量文件
var random=新的random();
const int lineCount=32000000;
var file=file.CreateText(“BigFile.txt”);
对于(变量i=0;i0;i--)
{
int j=随机。下一个(0,i+1);
//将i复制到temp
Buffer.BlockCopy(byteArray,sizeOfRecord*i,temp,0,sizeOfRecord);
//将j复制到i
Buffer.BlockCopy(byteArray,sizeOfRecord*j,byteArray,sizeOfRecord*i,sizeOfRecord);
//将温度复制到j
Buffer.BlockCopy(temp,0,byteArray,sizeOfRecord*j,sizeOfRecord);
}
}
}
所有行的长度是否相同?这将使它变得更容易…如果你只是在没有OrderBy的情况下执行“ReadAllLines”,会占用多少内存?这已经太多了吗?@ThomasLevesque yes所有行的大小都相同。@Baldrick yes无论OrderBy如何,都会发生这种情况。OrderBy(s=>random.Next())
不保证终止。OrderBy
子句中的函数应该提供总排序。看,为了做费舍尔·耶茨的洗牌,我不需要加载内存中的所有行,然后进行原地洗牌吗?或者,这可以在不加载文件的情况下完成吗memory@idipous,是的,您仍然需要加载内存中的所有行。这并不理想,但最好在加载时加载2到3次。@idipous,是的,对不起,我修复了它。是的,它只有相同长度的数字(例如,一个文件可以有32M 10位数字,另一个与第一个文件无关的文件可以有3M 9位数字)。我会尝试一下,让你知道。虽然你是对的,峰值内存约400米的输出文件是不正确的。。。我得到一个文件,里面有这样的东西47 30090968697002 3064902714 34101 30751697421430@idipous:嗯。。为我获得完美的输出。您是否使用我的精确样本看到该问题,或将其更改为与您的文件一起使用?请记住,如果行长为10个字符,则记录的大小应为12。您需要为行终止符增加2个字符。如果您也运行Mono,则可能会有所不同。注意:只是修复了临时字节数组声明中的错误-使其太大(不应影响您的输出,但值得注意),无法获取我所做的sizeofrecordsizeofrecord=System.Text.AscienceOding.ASCII.GetByteCount(行)代码>其中行来自文件读取,所有行大小相同,但编号不同,所以我只选择最后一行。如果获取长度的“行”是从“ReadLines”获取的字符串,那么它将不包括行终止符。这不包括在内。你可能需要在这个数字上加2。
public class Program
{
private static Random random = new Random();
public static void Main(string[] args)
{
// create massive file
var random = new Random();
const int lineCount = 32000000;
var file = File.CreateText("BigFile.txt");
for (var i = 0; i < lineCount ; i++)
{
file.WriteLine("{0}",i.ToString("D10"));
}
file.Close();
int sizeOfRecord = 12;
var loadedLines = File.ReadAllBytes("BigFile.txt");
ShuffleByteArray(loadedLines, lineCount, sizeOfRecord);
File.WriteAllBytes("BigFile2.txt", loadedLines);
}
private static void ShuffleByteArray(byte[] byteArray, int lineCount, int sizeOfRecord)
{
var temp = new byte[sizeOfRecord];
for (int i = lineCount - 1; i > 0; i--)
{
int j = random.Next(0, i + 1);
// copy i to temp
Buffer.BlockCopy(byteArray, sizeOfRecord * i, temp, 0, sizeOfRecord);
// copy j to i
Buffer.BlockCopy(byteArray, sizeOfRecord * j, byteArray, sizeOfRecord * i, sizeOfRecord);
// copy temp to j
Buffer.BlockCopy(temp, 0, byteArray, sizeOfRecord * j, sizeOfRecord);
}
}
}