2017-02-20 147 views
1

我正在尝试读取文件并生成一个没有包含“HEADER”或“TRAILER”的行的新文件。以下是我的代码。当我在文本[i] .Remove(i)处放置断点时,它似乎执行该代码,但文本变量不会删除该行。任何帮助将不胜感激。从文件C#File.ReadAllLines中删除头和尾部

 var text = File.ReadAllLines(fileName); 
     int i = 0; 
     foreach (string line in text) 
     { 
      if (line.Substring(0, 20).Contains("HEADER") || line.Substring(0, 20).Contains("TRAILER")) 
      { 
       text[i].Remove(i); 
      } 
      else 
      { 
      i++; 
      } 
     } 
     string newFN = fileName + "b"; 
     File.WriteAllLines(newFN, text); 
+1

不能修改枚举同时列举它。 – Amy

+1

另外'text [i] .Remove(i)'最有可能不会做你认为它做的事。 –

+2

也就是你调用'Remove'的方式,你会打电话给它(字符)一行本身。所以你要告诉该行删除在'text [i]'(一行)内的索引'i'处开始的字符。但是因为字符串是不可变的,所以你要返回一个新的字符串,并且不做任何事情。除了其他评论和答案中关于从可枚举中移除的内容之外,您还混合了两种不同类型的“Remove”。请参阅https://msdn.microsoft.com/en-us/library/9ad138yc(v=vs.110).aspx此外,您应该查看'string.StartsWith',因为您的行可能不是20个字符长,而'Substring'可能会失败。 – pinkfloydx33

回答

1
File.WriteAllLines(filename + "b", File.ReadAllLines(filename) 
    .Select(l => l.Substring(0, 20)) 
    .Where(s => !s.Contains("HEADER") && !s.Contains("TRAILER"))); 

选择新的输出可以在所有的行读,选择每行的前20个字符,然后用Where排除所有行,其中第一20个字符包含HEADER或TRAILER,然后将结果行写入文件。

+1

请注意,OP的代码是'line.Substring(0,20).Contains(“HEADER”)',它与'line.StartsWith(“HEADER”)'非常不同。他们的代码允许在前20个字符的任何位置找到标题,但是您的代码只允许它从位置0开始存在。 – Quantic

+1

好点 - 更正 – TVOHM

+0

优秀的答案,但我需要整行不只是前20个字符。我只是做。选择(l => l)和s.Substring(0,20).Contains – Missy

1

您无法在枚举器中更改枚举。创建新的可写集合并仅插入与谓词匹配的行,或者使用LINQ创建已应用标准的新枚举,然后将其映射到数组或列表或您需要的任何集合。

1

ReadAllLines返回一个字符串数组。您可以使用LINQ从text

var text = File.ReadAllLines(fileName).Select(i => {line.Contains("HEADER")? "": line}); 

File.WriteAllLines(newFN, text); 
1

我会使用ReadLines而不是ReadAllLines,因为它允许您列举它仍在读取更多文件行。这样,在开始写出新文件之前,您不必将整个文件读入内存。然后,您可以简化代码到这一行:

File.WriteAllLines(fileName + "b", File.ReadLines(fileName).Where(line => !line.Contains("HEADER") | !line.Contains("TRAILER"))); 

这将导致其写入新文件时离开了头部和尾部线条。

此外,要更全面地回答您的问题String.Remove将从索引中删除所有字符到字符串末尾并返回一个新字符串。 .Net中的字符串是不可变的,所以它不会修改当前字符串,只是给你一个新的字符串。另外,当您在比较中调用Substring时,这些方法正在创建新的字符串实例,仅供您检查字符串是否包含在该字符范围内。在字符串上调用Contains会更好。

1
var lines = File.ReadLines(fileName); 
var filtered = lines.Where(line => !line.Contains("HEADER") && !line.Contains("TRAILER"))); 
File.WriteAllLines(filename + "b", filtered);  // or filename.Replace(".txt", "b.txt") ? 

.Substring(0, 20)分配内存为新的字符串,将失败有少于20个字符的线条,所以在大多数情况下只是.Contains会更快。或者,你可以使用.IndexOf代替:

line.IndexOf("HEADER", 0, 20, StringComparison.OrdinalIgnoreCase) < 0 

我猜测,正则表达式可能会快一点,避免一些额外的内存分配的:

string text = File.ReadAllText(fileName); 
string[] parts = Regex.Split(text, @"\n?\r?.*(HEAD|TRAIL)ER.*\n?\r?"); 
File.WriteAllLines(filename + "b", parts);