在 C# 中高效读取具有一个标题和多个详细信息行的字符分隔文本文件

问题描述 投票:0回答:1

我需要逐行读取字符(^)分隔的文本文件并替换同一文件中的错误数据。我当前的程序可以做到这一点,但我想知道如果需要处理巨大的文本文件,是否有更有效的方法来做到这一点。

输入文件数据:

10^I^23231^LGGE^DTL^09595~
20^00001^11^0.03000^0.05000^0.40500^EXETER~
30^223312^R^700^12.90^10^~
40^R^70036700015^01~
50^00000^12~
30^000000^C^781^11.10^09~
40^R^70036700016^01~
50^00000^12~
90^007^20231208^090909^0001^11~

行号 10 表示标题,90 表示尾部,中间的所有内容都是详细信息行,每个行号对应于一个特定属性,如合同详细信息或订单详细信息或供应商详细信息。

我的代码查找不正确的供应商详细信息(即第 30 行)并检查第 2 列中的供应商编号是否有效。如果是 000000,则替换为默认值“221212”。对于下一个行号 30 循环重复此过程,直到 EOF。 这些行具有不同数量的实体,但具有相同起始行号的行具有相同数量的实体。 StreamReader 类确实可以工作,但是我想知道是否有更有效的解决方案可用。尝试了 FileHelpers dll,但无法让它按预期工作来获取和替换确切的值。

代码:

public chkfile()
{
    string[] ipFields = null;
    ArrayList nextpos = new ArrayList();
    StreamReader reader = new StreamReader("inputfile.txt");

    nextpos.Add("30");
    string res = string.Empty;

    while (reader.Peek() >= 0)
    {
        fileLine = reader.ReadLine().Trim();
        lineLength = fileLine.Length;
        int lineLength_a = fileLine.Length - 1;

        // Gets the ipFields from the file
        recordType = fileLine.Substring(0, 2);
        ipFields = fileLine.Substring(0, lineLength).Split
          (Configuration.ipFile.ColumnDelimiter.ToCharArray());

        if (fileLine.StartsWith("30") && nextpos.Contains("30"))
        {
            for (int i = 0; i < ipFields.Length; i++)
            {
                if (ipFields[i].Equals("000000"))
                {
                    ipFields[i] = ipFields[i].Replace(ipFields[i], "221212");
                }

            }
            res = string.Join(Configuration.ipFile.ColumnDelimiter, ipFields);

            ipFileContent = ipFileContent.Replace(fileLine, res);

            // Set the next expected record type
            nextpos.Clear();
            nextpos.Add("40");
        }
    }
}

public class ipFile
{
    /// <summary>
    /// Value that delimits the Rows
    /// </summary>
    public static string RowDelimiter
    {
        get { return "~"; }
    }

    /// <summary>
    /// Value that delimits the ipFields
    /// </summary>
    public static string ColumnDelimiter
    {
        get { return "^"; }
    }
}
c# .net delimiter streamreader filehelpers
1个回答
-1
投票

您上面提供的代码对于逐行处理输入文件并根据某些条件进行替换似乎是合理的。唯一的事情是你可以优化它。如果您正在处理非常大的文本文件,则应考虑一些优化:

1。内存使用情况:

  • 您可以使用
    ArrayList
    来加快查找速度,而不是使用
    nextpos
    来代替
    HashSet
  • 考虑使用
    StringBuilder
    构建修改后的内容。

2。文件输入/输出:

  • StreamReader
    包裹在
    using
    声明中,以确保完成后得到正确处置。
  • 如果要替换文件中的文本,您可能需要考虑将修改写入新文件,然后将其重命名为原始文件。这样,您就不需要在写回之前将整个文件读入内存。

以下是包含其中一些建议的示例:

public class chkfile
{
    public chkfile()
    {
        HashSet<string> nextpos = new HashSet<string> { "30" };

        using (StreamReader reader = new StreamReader("inputfile.txt"))
        using (StreamWriter writer = new StreamWriter("outputfile.txt"))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                string[] ipFields = line.Split(Configuration.ipFile.ColumnDelimiter.ToCharArray());

                if (line.StartsWith("30") && nextpos.Contains("30"))
                {
                    for (int i = 0; i < ipFields.Length; i++)
                    {
                        if (ipFields[i].Equals("000000"))
                        {
                            ipFields[i] = "221212";
                        }
                    }

                    line = string.Join(Configuration.ipFile.ColumnDelimiter, ipFields);

                    // Set the next expected record type
                    nextpos.Clear();
                    nextpos.Add("40");
                }

                writer.WriteLine(line);
            }
        }
    }
}

请记住将

outputfile.txt
替换为您想要的输出文件名。这种方法减少了内存使用量,尤其是在处理大文件时,并确保正确的文件 I/O 处理。

© www.soinside.com 2019 - 2024. All rights reserved.