【问题标题】:Replacing Multiple String Values in Files替换文件中的多个字符串值
【发布时间】:2015-11-22 02:49:28
【问题描述】:

我正在尝试清理我每季度收到的一些文件。他们有一堆重复的标题,我想一次替换多个字符串值。我可以一次删除一个字符串,但我不明白如何流式传输文件并查看每一行并删除它是字符串 1 还是字符串 2。

每个文件至少有 100-30 万行,每次大约每季度一次将数据转储给我时,我会得到 10 到 50 个文件...如果他们不添加这些行会更容易,但是不是一个选项。

对于新手问题,我很抱歉,但我不经常编写代码。任何帮助表示赞赏...

static void Main(string[] args)
{
    string tempFile = Path.GetTempFileName();
    string t1 = "-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";

    string fName = "C:\\PoC\\test\\test.txt";
    using (var sr = new StreamReader(fName))
    using (var sw = new StreamWriter(tempFile))
    {
        string line;

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

            if (line.Contains(t1) == false)
            {
                sw.WriteLine(line);
            }
        }
        sr.Close();
        sw.Close();
    }

    File.Delete(fName);
    File.Move(tempFile, fName);
}

【问题讨论】:

  • 请记住,每次读取时,您都会将流位置移动到最后一个字节 read 和 writeline 方法将从该位置写入。我的建议是在读取一行后密切关注起始位置和新位置,并根据您的 if 条件用空格覆盖该范围。如果您想直接执行此操作,也可以在内存上构建一个新文件并覆盖整个文件。

标签: c# text replace


【解决方案1】:

调用 string.Contains() 几乎与调用 string.Replace() 一样昂贵,因为在任何一种情况下,都必须扫描整行以查找您的子字符串。在 Replace() 找到匹配的情况下,它创建并返回一个表示替换结果的新字符串,否则它返回原始字符串。改变

if (line.Contains(t1) == false)
    sw.WriteLine(line);

sw.WriteLine(line.Replace(t1, whatYouWantToReplaceWith));

如果你在一行中替换多个值,你可以写

sw.WriteLine(
    line
    .Replace(t1, whatYouWantToReplaceWith1)
    .Replace(t2, whatYouWantToReplaceWith2)
    .Replace(t3, whatYouWantToReplaceWith3)
);

请注意,使用多个 .Replace() 将导致多次扫描该行以查找匹配项。虽然这会稍微降低性能,但您的大部分处理时间可能仍然是文件 IO。

如果您知道替换只会发生,例如在第一行中,您可以添加一个计数器来跟踪您所在的行号,并且只将 Replace() 代码应用于适当的行。

请注意,您可能通过using a BufferedStream 对大文件进行一些额外的改进。

更新

基于您只想删除该行的声明,我建议您使用@Eser 的答案。

【讨论】:

  • 好的,这是一个非常简单的方法......谢谢。一个问题,只需要删除字符串。那么我应该用什么来替换线呢?我尝试了以前有效的“线”(老实说,我不知道为什么)。我也试过“”。但这留下了一个空白行,我想完全删除该行。
  • 使用string.Replace(t1, "")
  • 埃里克,把我弄丢了。你是说 line.replace 到 string.replace 吗?抱歉这个愚蠢的问题。
  • 如果您只想删除 t1 中的任何内容,请使用 string.Replace(t1, "")。您是在匹配时尝试删除整行,还是仅从行中删除t1 中的内容但保留行的其余部分?
  • 只需删除该行。对不起,如果我没有说清楚。
【解决方案2】:

我知道您正在开发 ac# 程序,如果目的只是删除与模式匹配的行,那么我会使用 Unix Stream editor sed 命令,请参阅 sed for Windows stand alone commandcygwin您可以简单地使用该命令删除与模式匹配的所有行以及其后的行,您可以编写一个 .bat 脚本来复制、重命名、删除匹配多个模式的行。它也非常快。

sed -i '/^---------/d' filepath

【讨论】:

  • 这真的很有趣......我将不得不调查它。谢谢。
  • 如果 C# 程序是一个独立的东西,sed 是一个不错的选择。如果它是已经部署的软件包的一部分,我不会安装额外的东西。
  • 这只是简化我生活的一种方式。我将文件下载到我的计算机(1-5 GB),清理,然后加载到数据库中。它丑陋,但它就是这样......这些文件是日志文件转储,我的管理层想要一份关于它们的报告。我之前的那个人在记事本中使用了 find 并花了一两天的时间来做这件事……只是想在这里变得聪明。所以创建一个bat文件来处理它很有趣......我也想学习更多编码,所以现在两者都很棒。这是第一步,接下来是多个文件,然后自动加载到 DB...
  • 适用于个人环境或小型企业。对于大型企业来说,你拥有的组件越多,它就越复杂。部署它们,确保你有最新的安全补丁,等等。我是 sed 的粉丝,只是建议注意它是否是 OP 的最佳解决方案。
【解决方案3】:

我想一次替换多个字符串值。

使用 Linq 可以让你的代码更简单

string[] stringsToRemove = new[] { "str1", "str2", "str2" };

var query = File.ReadLines(fName)
                .Where(line => !stringsToRemove.Any(s => line.Contains(s)));

File.WriteAllLines(tempFile, query);

【讨论】:

  • 他在评论中澄清说他确实想删除整行而不是替换标记,所以你对这个问题的看法是正确的。
  • 我收到一个未处理的异常错误。有什么想法吗?System.IO.IOException 未处理 HResult=-2147024864 消息=进程无法访问文件 'C:\Users\xxxx\AppData\Local\Temp\tmpB784.tmp',因为它正被另一个进程使用。来源=mscorlib
  • @StuRyan 关闭/打开您的 VS 并重试...。看来,它与您编写的代码无关
  • @Eser 试过了……还是一样的异常。
猜你喜欢
  • 2019-01-07
  • 1970-01-01
  • 1970-01-01
  • 2018-10-29
  • 2021-10-21
  • 2015-03-30
  • 2020-12-04
  • 1970-01-01
相关资源
最近更新 更多