给定一个文本文件,我将如何读取文件中的任意行?
说,我有一个文件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 行的情况下重新编写它?
答案 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循环中的索引调用任何行范围。
解决方案非常好,但两者之间存在内存消耗。
试一试......值得吗