我有一个大型文本文件,需要搜索特定的字符串。是否有一种快速的方法可以不逐行读取而完成?
由于文件大小超过100MB,这种方法非常缓慢。
我有一个大型文本文件,需要搜索特定的字符串。是否有一种快速的方法可以不逐行读取而完成?
由于文件大小超过100MB,这种方法非常缓慢。
public static int FindInFile(string fileName, string value)
{ // returns complement of number of characters in file if not found
// else returns index where value found
int index = 0;
using (System.IO.StreamReader reader = new System.IO.StreamReader(fileName))
{
if (String.IsNullOrEmpty(value))
return 0;
StringSearch valueSearch = new StringSearch(value);
int readChar;
while ((readChar = reader.Read()) >= 0)
{
++index;
if (valueSearch.Found(readChar))
return index - value.Length;
}
}
return ~index;
}
public class StringSearch
{ // Call Found one character at a time until string found
private readonly string value;
private readonly List<int> indexList = new List<int>();
public StringSearch(string value)
{
this.value = value;
}
public bool Found(int nextChar)
{
for (int index = 0; index < indexList.Count; )
{
int valueIndex = indexList[index];
if (value[valueIndex] == nextChar)
{
++valueIndex;
if (valueIndex == value.Length)
{
indexList[index] = indexList[indexList.Count - 1];
indexList.RemoveAt(indexList.Count - 1);
return true;
}
else
{
indexList[index] = valueIndex;
++index;
}
}
else
{ // next char does not match
indexList[index] = indexList[indexList.Count - 1];
indexList.RemoveAt(indexList.Count - 1);
}
}
if (value[0] == nextChar)
{
if (value.Length == 1)
return true;
indexList.Add(1);
}
return false;
}
public void Reset()
{
indexList.Clear();
}
}
你的项目需要每次搜索不同的文件以查找相同或不同的字符串,还是每次搜索相同的文件以查找不同的字符串?
如果是后者,你可以建立文件的索引。但是,如果文件经常更改,建立索引就没有意义,因为建立索引会很昂贵。
要为全文搜索索引文件,你可以使用Lucene.NET库。
byte[] lookingFor = System.Text.Encoding.UTF8.GetBytes("hello world");
int index = 0;
int position = 0;
bool matchFound = false;
using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
{
while (fileStream.ReadByte() == lookingFor[index])
{
index++;
if (index == lookingFor.length)
{
matchFound = true;
position = File.position - lookingFor.length;
break;
}
}
}
这是其中一个算法,你可以使用它(虽然长度检查可能会差一个)。它只会找到第一个匹配项,所以你可能需要将while循环包装在另一个循环中以查找多个匹配项。
另外,关于逐行读取文件的一件事情是,如果要匹配的字符串跨越多行,那么你将找不到它。如果这没问题,那么你可以逐行搜索,但如果你需要搜索字符串跨越多行,你将想使用类似上面详细说明的算法。
最后,如果你正在寻找最佳速度,听起来像是这样,你将想将以上代码迁移到使用StreamReader或其他缓冲读取器。
/// <summary>
/// Find <paramref name="toFind"/> in <paramref name="reader"/>.
/// </summary>
/// <param name="reader">The <see cref="TextReader"/> to find <paramref name="toFind"/> in.</param>
/// <param name="toFind">The string to find.</param>
/// <returns>Position within <paramref name="reader"/> where <paramref name="toFind"/> starts or -1 if not found.</returns>
/// <exception cref="ArgumentNullException">When <paramref name="reader"/> is null.</exception>
/// <exception cref="ArgumentException">When <paramref name="toFind"/> is null or empty.</exception>
public int FindString(TextReader reader, string toFind)
{
if(reader == null)
throw new ArgumentNullException("reader");
if(string.IsNullOrEmpty(toFind))
throw new ArgumentException("String to find may not be null or empty.");
int charsRead = -1;
int pos = 0;
int chr;
do
{
charsRead++;
chr = reader.Read();
pos = chr == toFind[pos] ? pos + 1 : 0;
}
while(chr >= 0 && pos < toFind.Length);
int result = chr < 0 ? -1 : charsRead - toFind.Length;
return result < 0 ? -1 : result;
}