我在文本文件中搜索字符串(也包括XML)。这是我首先想到的:
using (StreamReader sr = File.OpenText(fileName))
{
string s = String.Empty;
while ((s = sr.ReadLine()) != null)
{
if (s.Contains("mySpecialString"))
return true;
}
}
return false;
我想逐行阅读,以尽量减少使用的RAM量。找到字符串后,应该中止操作。我不将其作为XML处理的原因是因为它必须被解析并且还会根据需要消耗更多内存。
另一个简单的实现是
bool found = File.ReadAllText(path).Contains("mySpecialString") ? true : false;
但是这会将完整的文件读入内存,这不是我想要的。另一方面,它可能会有性能提升。
另一个就是这个
foreach (string line in File.ReadLines(path))
{
if (line.Contains("mySpecialString"))
{
return true;
}
}
return false;
但是他们中的哪一个(或者你的另一个?)的内存效率更高?
答案 0 :(得分:3)
您可以使用File.ReadLines
的查询,因此它只会读取所需的行数,以满足您的查询。当Any()
方法遇到包含您的字符串的行时,它将停止。
return File.ReadLines(fileName).Any(line => line.Contains("mySpecialString"));
答案 1 :(得分:2)
我也更喜欢接受的答案。也许我在这里微观化了一些东西,但你已经要求一种记忆效率高的方法。另外请考虑您正在搜索的文字也可能包含新行字符,例如'\r'
,'\n'
或"\r\n"
,理论上大文件可能包含一行,否定ReadLines
的好处1}}。
所以你可以使用这种方法:
public static bool FileContainsString(string path, string str, bool caseSensitive = true)
{
if(String.IsNullOrEmpty(str))
return false;
using (var stream = new StreamReader(path))
while (!stream.EndOfStream)
{
bool stringFound = true;
for (int i = 0; i < str.Length; i++)
{
char strChar = caseSensitive ? str[i] : Char.ToUpperInvariant(str[i]);
char fileChar = caseSensitive ? (char)stream.Read() : Char.ToUpperInvariant((char)stream.Read());
if (strChar != fileChar)
{
stringFound = false;
break; // break for-loop, start again with first character at next position
}
}
if (stringFound)
return true;
}
return false;
}
bool containsString = FileContainsString(path, "mySpecialString", false); // ignore case if desired
请注意,这可能是最有效的方法,并且隐藏在方法中也是可读的。但它有一个缺点,实施文化敏感的比较是不可行的,因为它看的是单个字符而不是子字符串。
因此,您必须记住一些可以遇到问题的边缘情况,例如famous turkish i example或surrogate pairs。
答案 2 :(得分:1)
我认为你的解决方案都是一样的。请阅读MSDN:https://msdn.microsoft.com/en-us/library/dd383503%28v=vs.110%29.aspx
它说:&#34; ReadLines和ReadAllLines方法的不同之处如下:当您使用ReadLines时,您可以在返回整个集合之前开始枚举字符串集合&#34;
同一篇文章还建议ReadLines应与LINQ to Objects一起使用。