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

これは、ファイルを2回繰り返すソリューションです(最初は行を数え、次に行を選択します)。利点は、メモリ内に 3000 個の文字列の配列を作成する必要がないことです。ただし、前述のとおり、速度が遅くなる可能性があります。なぜ可能性がありますか?-File.ReadAllLines内部に文字列のリストを作成し、そのリストは 3000 個の項目でいっぱいになるまで何度もサイズ変更されるためです。(初期容量は になります4。内部配列が完全に満たされると、2 倍のサイズの新しい配列が作成され、すべての文字列がそこにコピーされます)。

したがって、ソリューションでは、必要のない行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

これを 1 回のパスで解決するには、Reservoir Samplingを使用します。

リストの長さが事前にわからない項目のリストから 1 つ以上の項目をランダムに選択する場合は、Reservoir Samplingを使用できます。

これを (メモリ内のすべての行のバッファリングを回避する) メソッドと共に利用して、File.ReadLines()バッファリングせずに各行を 1 回だけ読み取るシングルパス アルゴリズムを作成できます。

以下のサンプル コードは、任意の数の行をランダムに選択できる一般化されたソリューションを示しています。あなたの場合、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 に答える
0

ストリームを StreamReader にラップし、必要な回数だけ ReadLine を呼び出して、ターゲット行に移動できます。そうすれば、ファイルの内容全体をメモリに保持する必要がなくなります。

ただし、これはめったに行わず、ファイルが非常に大きい場合にのみ実行可能です。

于 2013-04-03T11:56:02.510 に答える
-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 に答える