Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从大文本文件中读取随机行_C#_Text Files - Fatal编程技术网

C# 从大文本文件中读取随机行

C# 从大文本文件中读取随机行,c#,text-files,C#,Text Files,我有一个5000多行的文件。我想找到最有效的方法,在每次运行程序时从这些行中选择一行。我原本打算使用随机方法选择一个(那是在我知道有5000行之前)。我认为这样做可能效率不高,所以我想我应该阅读第一行,然后从顶部删除它并将其添加到底部。但似乎我必须阅读整个文件,并创建一个新文件从顶部删除 最有效的方法是什么:随机方法还是新文件方法 该程序将每5分钟运行一次,我使用的是c#4.5,我假设目标是从5000多行的文件中随机选择一行 试试这个: 使用File.ReadLines(File.count()

我有一个5000多行的文件。我想找到最有效的方法,在每次运行程序时从这些行中选择一行。我原本打算使用随机方法选择一个(那是在我知道有5000行之前)。我认为这样做可能效率不高,所以我想我应该阅读第一行,然后从顶部删除它并将其添加到底部。但似乎我必须阅读整个文件,并创建一个新文件从顶部删除

最有效的方法是什么:随机方法还是新文件方法


该程序将每5分钟运行一次,我使用的是c#4.5,我假设目标是从5000多行的文件中随机选择一行

试试这个:

  • 使用File.ReadLines(File.count()获取行数
  • 使用行数作为上限,生成一个随机数
  • 使用file.ReadLines(file)对文件进行延迟读取
  • 使用随机数从此数组中选择一行

  • 编辑:如前所述,执行File.ReadLines(File).toArray()非常低效。

    在.NET 4.*中,可以直接访问文件的一行。例如,要获取第X行:

    string line = File.ReadLines(FileName).Skip(X).First();
    
    完整示例:

    var fileName = @"C:\text.txt"
    var file = File.ReadLines(fileName).ToList();
    int count = file.Count();
    Random rnd = new Random();
    int skip = rnd.Next(0, count);
    string line = file.Skip(skip).First();
    Console.WriteLine(line);
    

    以下是对问题的评论中提出的方法的快速实施:

    // open the file
    using(FileStream stream = File.OpenRead("yourfile.dat"))
    {
        // 1. index all offsets that are the beginning of a line
        List<Long> lineOffsets = new List<Long>();
        lineOffsets.Add(stream.Position); //the very first offset is a beginning of a line!
        int ch;
        while((ch = stream.ReadByte()) != -1) // "-1" denotes the end of the file
        {
            if(ch == '\n')
                lineOffsets.Add(stream.Position);
        }
    
        // 2. read a random line
        stream.Seek(0, SeekOrigin.Begin); // go back to the beginning of the file
        // set the position of the stream to one the previously saved offsets
        stream.Position = lineOffsets[new Random().Next(lineOffsets.Count)];
        // read the whole line from the specified offset
        using(StreamReader reader = new StreamReader(stream))
        {
            Console.WriteLine(reader.ReadLine());
        }
    }
    
    //打开文件
    使用(FileStream stream=File.OpenRead(“yourfile.dat”))
    {
    //1.索引作为直线起点的所有偏移
    List lineoffset=新列表();
    lineoffset.Add(stream.Position);//第一个偏移量是一行的开始!
    int-ch;
    而((ch=stream.ReadByte())!=-1)/“-1”表示文件的结尾
    {
    如果(ch='\n')
    lineoffset.Add(stream.Position);
    }
    //2.随机读一行
    stream.Seek(0,SeekOrigin.Begin);//返回文件的开头
    //将流的位置设置为先前保存的偏移之一
    stream.Position=lineoffset[new Random().Next(lineoffset.Count)];
    //从指定的偏移量读取整行
    使用(StreamReader=新StreamReader(stream))
    {
    Console.WriteLine(reader.ReadLine());
    }
    }
    

    目前我附近没有任何VS,因此这是未经测试的。

    假设文件太大,您无法将其装入RAM。然后,您可能希望使用一种算法,该算法设计用于处理从未知、任意长度的列表中随机选取可能不适合内存的内容:

    Random r = new Random();
    int currentLine = 1;
    string pick = null;
    foreach (string line in File.ReadLines(filename)) 
    {
        if (r.Next(currentLine) == 0) {
            pick = line;
        }
        ++currentLine;
    }   
    return pick;
    
    在较高的水平上,储层取样遵循一个基本规则:每增加一条线,就有1/N的机会替换所有先前的线

    这个算法有点不直观。在较高的级别上,它的工作原理是使第N行有1/N的机会替换当前选定的行。因此,第1行有100%的几率被选中,但之后被第2行取代的几率为50%

    我发现以正确性证明的形式理解这个算法是最容易的。因此,一个简单的归纳证明:

    1) 基本情况:通过检查,如果有一行,则算法有效。
    2) 如果算法适用于N-1行,则处理N行是有效的,因为:
    3) 处理N行文件的N-1次迭代后,所有N-1行的可能性相同(概率为1/(N-1))。
    4) 下一次迭代确保第N行的概率为1/N(因为这是算法明确指定的,并且是最终迭代),从而将所有前一行的概率降低为:

    1/(N-1) * (1-(1/N))  
    1/(N-1) * (N/N-(1/N))  
    1/(N-1) * (N-1)/N  
    (1*(N-1)) / (N*(N-1))  
    1/N
    

    如果您事先知道文件中有多少行,则此算法的开销比需要的要大,因为它总是读取整个文件。

    查找文件中的随机偏移量,然后向前扫描换行符。读取数据直到下一个换行符。在文件结束时采取预防措施。但是,如果这些线的长度差异很大,概率就不一样了。哦,5000不是那么多;-)将其拆分为50个文件,每个文件有100行,文件为随机编号0-50,行为随机编号0-99。尽管如此,每5分钟阅读5000行仍然不是一个大问题。。。效率不高,但不是真正的问题。如果这是应用程序的唯一问题,那么你很好:)文件总共有多大?正如@Lucastzesniewski所写,你应该在文件中寻找一个随机偏移量。但请记住,如果您的文件采用可变字符长度编码(如UTF-8),则此解决方案不起作用。效率是性能与成本的衡量标准,但您没有说明您感兴趣的性能方面或成本方面。如果你不能描述性能和成本,那么没有人能为你回答这个问题;如果你能同时衡量这两个方面,那么你就会知道答案。从目前评论中提出的所有问题来看,这将是最低效的解决方案。您对
    File.ReadLines的两个调用都将读取整个文件(调用
    ToArray
    会使步骤3变得非常懒惰)-除此之外:是的,您假设正确,因为这正是他所要求的,绝对正确。我将删除ToArray()方法调用。但是你也说得对,无论如何这并不是最有效的方法。但是你还是多次读取了文件:
    file.ReadAllLines
    会更快,就像我不会执行file.ReadAllLines一样,因为这样会返回一个巨大的数组(这也是file.ReadLines().toArray()所做的)。使用FIle.readLines的要点是它返回一个IEnumerable。例如:我很清楚。。。根据硬件的不同,对于
    File.ReadLines(FileName).Skip(X).Take(1).First()
    可以简化为
    File.ReadLines(FileName).Skip(X).First()
    您的完整示例是将整个文件读入内存两次。没错,我已经编辑了代码。通过只读取一次文件,我的系统上的执行时间从~8毫秒变为~6毫秒。谢谢你也已经声明了两次
    var文件
    ,但是