8

我有一个超过 3000 行的文本文件。我正在使用

string[] lines = File.ReadAllLines(myPath);
var lineCount = lines.Length; 

然后我生成一个随机数

Random rand = new Random();
var lineToRead = rand.Next(1, lineCount);

现在我需要读取由随机数生成的特定行。我可以使用

string requiredLine = lines[lineToRead];

因为我的文件很大,所以我不认为创建这么大的数组是有效的。有没有更有效或更简单的方法来做到这一点?

4

6 回答 6

10

这是一个迭代文件两次的解决方案(第一次计算行数,下一次选择行)。好处是您不需要在内存中创建一个包含 3000 个字符串的数组。但是,如上所述,它可能会更慢。为什么可能?- 因为File.ReadAllLines在里面创建了一个字符串列表,并且该列表将在填充 3000 个项目时多次调整大小。(初始容量为4。当内部数组完全填满时,将创建两倍大小的新数组,并将所有字符串复制到那里)。

因此,该解决方案使用File.ReadLines返回IEnumerable<string>行并跳过您不需要的行的方法:

IEnumerable<string> lines = File.ReadLines(myPath);
var lineToRead = rand.Next(1, lines.Count());
var line = lines.Skip(lineToRead - 1).First();

顺便说一句,内部File.ReadLines使用SteamReader它逐行读取文件。

于 2013-04-03T11:57:20.180 回答
1

您可以做的是解析文件以查找每一行的索引,然后您可以稍后通过使用 Stream.Position 获取内容返回到某一行。使用这种方法,您不需要在内存中保留任何内容,而且速度相当快。我在一个 20K 行和 1MB 大小的文件上对此进行了测试。索引文件需要 7 毫秒,获取行需要 0.3 毫秒。

    // Parse the file
    var indexes = new List<long>();
    using (var fs = File.OpenRead("text.txt"))
    {
        indexes.Add(fs.Position);
        int chr;
        while ((chr = fs.ReadByte()) != -1)
        {
            if (chr == '\n')
            {                        
                indexes.Add(fs.Position);
            }
        }
    }

    int lineCount = indexes.Count;
    int randLineNum = new Random().Next(0, lineCount - 1);
    string lineContent = "";


    // Read the random line
    using (var fs = File.OpenRead("text.txt"))
    {
        fs.Position = indexes[randLineNum];
        using (var sr = new StreamReader(fs))
        {
            lineContent = sr.ReadLine();
        }
    }
于 2013-04-03T14:40:52.860 回答
0

您可以将流包装到 StreamReader 中,并根据需要多次调用 ReadLine 以转到目标行。这样您就不需要将整个文件内容保存在内存中。

但是,这只有在您很少这样做并且文件很大时才可行。

于 2013-04-03T11:56:02.510 回答
0

使用Reservoir Sampling一次性解决此问题

如果您想从事先不知道该列表长度的项目列表中随机选择一个或多个项目,您可以使用Reservoir Sampling

我们可以利用这一点,连同File.ReadLines()方法(避免缓冲内存中的所有行)编写一个单遍算法,该算法将只读取每行一次,而不进行缓冲。

下面的示例代码显示了一个通用解决方案,可让您随机选择任意数量的行。对于您的情况,N = 1。

示例代码还包括一个测试程序,以证明这些行是随机选择的,分布均匀。

(要了解此代码的工作原理,请参阅我上面链接的 Wiki 文章。)

using System;
using System.IO;
using System.Collections.Generic;

namespace Demo
{
    internal class Program
    {
        public static List<string> RandomlyChooseLinesFromFile(string filename, int n, Random rng)
        {
            var result = new List<string>(n);
            int index = 0;

            foreach (var line in File.ReadLines(filename))
            {
                if (index < n)
                {
                    result.Add(line);
                }
                else
                {
                    int r = rng.Next(0, index + 1);

                    if (r < n)
                        result[r] = line;
                }

                ++index;
            }

            return result;
        }

        // Test RandomlyChooseLinesFromFile()

        private static void Main(string[] args)
        {
            Directory.CreateDirectory("C:\\TEST");
            string testfile = "C:\\TEST\\TESTFILE.TXT";
            File.WriteAllText(testfile, "0\n1\n2\n3\n4\n5\n6\n7\n8\n9");
            var rng = new Random();
            int trials = 100000;
            var counts = new int[10];

            for (int i = 0; i < trials; ++i)
            {
                string line = RandomlyChooseLinesFromFile(testfile, 1, rng)[0];
                int index = int.Parse(line);
                ++counts[index];
            }

            // If this algorithm is correct, each line should be chosen
            // approximately 10% of the times.

            Console.WriteLine("% times each line was chosen:\n");

            for (int i = 0; i < 10; ++i)
            {
                Console.WriteLine("{0} = {1}%", i, 100*counts[i]/(double)trials);
            }
        }
    }
}
于 2013-04-03T13:02:16.587 回答
-1

下面将帮助您阅读文件中的特定行。

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/4dbd68f6-61f5-4d36-bfa0-5c909101874b

一段代码

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ReadLine
{
class Program
{
    static void Main(string[] args)
    {
        //Load our text file
        TextReader tr = new StreamReader("\\test.txt");

        //How many lines should be loaded?
        int NumberOfLines = 15;

        //Make our array for each line
        string[] ListLines = new string[NumberOfLines];

        //Read the number of lines and put them in the array
        for (int i = 1; i < NumberOfLines; i++)
        {
            ListLines[i] = tr.ReadLine();
        }

        //This will write the 5th line into the console
        Console.WriteLine(ListLines[5]);
        //This will write the 1st line into the console
        Console.WriteLine(ListLines[1]);

        Console.ReadLine();

        // close the stream
        tr.Close();
    }
}
}

这些也可以有帮助..

http://www.tek-tips.com/viewthread.cfm?qid=1460456

如何读取文本文件中的指定行?

下面是编辑

在 C# 中编辑文本文件的特定行

希望能帮助到你...

于 2013-04-03T11:58:46.497 回答
-1

你可以像下面这样尝试......它不能创建任何大数组,但会得到一个特定的行......

string path = "D:\\Software.txt";
int lines = File.ReadAllLines(path).Length;
Random rand = new Random();
var lineToRead = rand.Next(1, lines);
var requiredLine = System.IO.File.ReadLines(path).Skip(lineToRead - 1).First();
Console.WriteLine(requiredLine.ToString());
于 2013-04-03T12:26:24.543 回答