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

时间:2009-08-11 21:14:24

标签: c# string file-io input

给定一个文本文件,我将如何读取文件中的任意行?

说,我有一个文件test.txt。我该如何阅读文件中的第15行?

我所见过的是涉及将整个文本文件存储为String数组然后使用行号的值作为要从数组中使用的String的数量的东西...但是有一些复杂情况:文本文件非常庞大,我编码的应用程序的机器并不是一流的系统。速度不是首要任务,但绝对是一个主要问题。

有没有办法读取文本文件的特定行并将结果存储为字符串?

感谢您的回复: 该文件是KINDA结构化的。它有25行信息,然后是 X 数字行,但前25行中的第17行的值为 X

但是,有一个空白行,它作为文件中的第二条记录重复自身, X 可以为每条记录赋予不同的值。

我想要做的是读取并存储前25行作为独立值,然后将下一个 X (通常约250)行存储为数组。然后我将它存储在SQL数据库中并重复使用NEXT记录,直到我到达 Y th记录(文件中的记录数在第3行)

编辑2 : 好吧,我想我已经找到了基于你所有人的回应的解决方案。

我将阅读前25行并将其存储为数组。我将数组的相关内容复制到局部变量然后我将删除前25行。然后,我可以使用info将下一个 X 行(数组中的第13项的值)存储为数组,将其序列化,将其存储在数据库中,然后删除我刚刚读取的行

然后,我可以为每个后续记录重复此过程。

当然,这取决于我正在做的一个假设,说实话,我不确定是否属实。是否可以从C#中的文本文件中删除第一个 n 行而不必读取整个内容并在没有第一个 n 行的情况下重新编写它?

14 个答案:

答案 0 :(得分:93)

.NET 4.0编辑

从.NET 4.0开始,可以直接访问文件的单行。例如,访问第15行:

string line = File.ReadLines(FileName).Skip(14).Take(1).First();

这将只返回所需的行


由于你无法预测文件中第i行的位置(可以吗?),你也必须阅读所有以前的行。如果行号很小,这可能比ReadAllLines方法更有效。

string GetLine(string fileName, int line)
{
   using (var sr = new StreamReader(fileName)) {
       for (int i = 1; i < line; i++)
          sr.ReadLine();
       return sr.ReadLine();
   }
}

答案 1 :(得分:12)

如果每一行都是固定长度,那么你可以在它周围打开一个Stream,在文件中寻找(每行字节数)* n并从那里读取你的行。

using( Stream stream = File.Open(fileName, FileMode.Open) )
{
    stream.Seek(bytesPerLine * (myLine - 1), SeekOrigin.Begin);
    using( StreamReader reader = new StreamReader(stream) )
    {
        string line = reader.ReadLine();
    }
}

或者你可以使用StreamReader读取行,直到找到你想要的行。这种方式比较慢,但仍然比读取每一行都有所改进。

using( Stream stream = File.Open(fileName, FileMode.Open) )
{
    using( StreamReader reader = new StreamReader(fileStream) )
    {
        string line = null;
        for( int i = 0; i < myLineNumber; ++i )
        {
            line = reader.ReadLine();
        }
    }
}

答案 2 :(得分:4)

不幸的是没有。在原始级别文件不适用于行号。相反,它们以位置/偏移为基础工作。根文件系统没有行的概念。它是由更高级别组件添加的概念。

所以无法告诉操作系统,请打开文件行。相反,您必须打开文件并跳过计算新行,直到您通过指定的数字。然后将下一组字节存储到一个数组中,直到您点击下一个新行。

答案 3 :(得分:3)

除非你有固定尺寸的线,否则你需要读取每一行,直到你到达你想要的线。虽然,您不需要存储每一行​​,但如果它不是您想要的行,则只需将其丢弃。

编辑:

如上所述,如果行长度是可预测的,也可以在文件中查找 - 也就是说你可以应用一些确定性函数将行号转换为文件位置。

答案 4 :(得分:2)

正如Mehrdad所说,你不能只是在没有阅读文件的情况下寻找第n行。 但是,您不需要将整个文件存储在内存中 - 只需丢弃您不需要的数据。

string line;
using (StreamReader sr = new StreamReader(path))
    for (int i = 0; i<15; i++)
    {
       line = sr.ReadLine();
       if (line==null) break; // there are less than 15 lines in the file
    }

答案 5 :(得分:2)

每次阅读五行,只需将你的陈述放在if语句中,就是这样

        String str1 = @"C:\Users\TEMP\Desktop\StaN.txt";   

        System.IO.StreamReader file = new System.IO.StreamReader(str1);

        line = file.ReadLine();

        Int32 ctn=0;

        try
        {

            while ((line = file.ReadLine()) != null)
            {

                    if (Counter == ctn)
                    {
                        MessageBox.Show("I am here");
                        ctn=ctn+5;
                        continue;
                    }
                    else
                    {
                        Counter++;
                        //MessageBox.Show(Counter.ToString());
                        MessageBox.Show(line.ToString());
                    } 
                }

            file.Close();
        }
        catch (Exception er)
        {

        }

答案 6 :(得分:1)

如果这些行都是固定长度,您可以使用流的Seek方法移动到正确的起始位置。

如果线条长度可变,则您的选项会受到更多限制。

如果这是一个文件,你将只使用一次,然后丢弃,那么你最好阅读它并在记忆中使用它。

如果这是一个文件,您将保留并将从而不是写入,您可以创建一个自定义索引文件,其中包含每行的起始位置。然后使用该索引获取您的Seek位置。创建索引文件的过程是资源密集型的。每次向文件添加新行时,都需要更新索引,因此维护成为一个非常重要的问题。

答案 7 :(得分:0)

您可以逐行阅读,这样您就不必一次阅读所有内容(可能完全阅读)

int i=0
while(!stream.eof() && i!=lineNum)
    stream.readLine()
    i++
line = stream.readLine()

答案 8 :(得分:0)

如果您的文件包含不同长度的行,并且您需要经常读取行并且需要快速阅读它,您可以通过读取一次来创建文件的索引,保存每个新行的位置,然后在需要时读取一行,你只需在索引中查找该行的位置,在那里寻找,然后你读取该行。

如果向文件中添加新行,则只需添加新行的索引即可,无需重新编制索引。虽然如果你的文件在某个行中的某个地方发生变化,你已经编入索引,那么你必须重新索引。

答案 9 :(得分:0)

虽然你不能直接在非对称文件中寻找第N行而不读取文件中的数据(因为你需要计算你已经进入文件的行数),你可以计算换行直到你到达你想要的线路,它占用最少的内存并且可能具有最佳性能。

这比读取数组中的所有内容更具内存效率,因为它只会读到文件,直到它到达文件的末尾或行号(以先到者为准)。它远非完美,但可能适合您的需求:

string line15 = ReadLine(@"C:\File.csv", 15);

public string ReadLine(string FilePath, int LineNumber){
    string result = "";
    try{
    if( File.Exists(FilePath) ){
        using (StreamReader _StreamReader = new StreamReader(FilePath)){
        for (int a = 0; a < LineNumber; a++) {
            result = _StreamReader.ReadLine();
        }
        }
    }
    }catch{}
    return result;
}

答案 10 :(得分:0)

试过并测试过。它很简单如下:

string line = File.ReadLines(filePath).ElementAt(actualLineNumber - 1);

只要你有一个文本文件,这应该有效。 之后,根据您希望读取的数据,您可以相应地转换字符串并使用它。

答案 11 :(得分:0)

变种。如果行号大于行数,则产生错误。

string GetLine(string fileName, int lineNum)
{
    using (StreamReader sr = new StreamReader(fileName))
    {
        string line;
        int count = 1;
        while ((line = sr.ReadLine()) != null)
        {
            if(count == lineNum)
            {
                return line;
            }
            count++;
        }
    }
    return "line number is bigger than number of lines";  
}

答案 12 :(得分:-1)

        if (File.Exists(fpath))
        {

            var data = File.ReadLines(fpath);
            Console.WriteLine(data.ToArray()[14]);
        }

答案 13 :(得分:-2)

迟到的答案,但值得。

您需要在数组或列表对象中加载行,其中每行将分配给索引,然后只需通过for循环中的索引调用任何行范围。

解决方案非常好,但两者之间存在内存消耗。

试一试......值得吗