如何逐行读取并替换文本文件中的字符串?

8
我有一个文本文件,内容是这样的:
INSERT INTO `shops` VALUES ('', '3', '1000000', '0');
INSERT INTO `shops` VALUES ('', '3', '1000010', '0');
INSERT INTO `shops` VALUES ('', '3', '1000020', '0');
INSERT INTO `shops` VALUES ('', '3', '1000030', '0');
INSERT INTO `shops` VALUES ('', '3', '1001000', '0');

注意每行的第一个键是''。对于每一行,我想找到那个'',并将其替换为一个数字(从1开始),然后在下一行继续加1,就像这样:

INSERT INTO `shops` VALUES ('1', '3', '1000000', '0');
INSERT INTO `shops` VALUES ('2', '3', '1000010', '0');
INSERT INTO `shops` VALUES ('3', '3', '1000020', '0');
INSERT INTO `shops` VALUES ('4', '3', '1000030', '0');
INSERT INTO `shops` VALUES ('5', '3', '1001000', '0');

我已经尝试了几个小时,但是一直失败。

这是我一直在思考的内容(我知道这远离正确,但是我不太精通c#,所以也许你们中的一个可以帮助我想出正确的代码):

string text = File.ReadAllText("C:\\Users\\Donavon\\Desktop\\old.sql");

int i = 0;
text = text.Replace("('',", "('" + i + "',");
i++;
File.WriteAllText("C:\\Users\\Donavon\\Desktop\\new.sql", text);

感谢任何帮助,非常感激。

你为什么一开始就有这样的文件? - juharr
9个回答

10
您会想要按照以下方式进行操作:
var lineNumber = 0;

using (var newFile = File.AppendText(@"c:\temp\new.sql"))
{
    foreach (var line in File.ReadLines(@"c:\temp\old.sql"))
    {
        lineNumber++;

        var updatedLine = line.Replace("('',", "('" + lineNumber.ToString() + "',");

        newFile.WriteLine(updatedLine);
    }
}

使用File.ReadLines方法读取大文件,可以避免内存不足的异常。

专业提示:在处理许多大文件时,请使用此方法。文件流是您的好朋友。 - slumtrimpet

6

您可以逐行阅读:

string text = "";
using (StreamReader sr = new StreamReader("C:\\Users\\Donavon\\Desktop\\old.sql"))
{
    int i = 0;
    do
    {
        i++;
        string line = sr.ReadLine();
        if (line != "")
        {
            line = line.Replace("('',", "('" + i + "',");
            text = text + line + Environment.NewLine;
        }
    } while (sr.EndOfStream == false);
}
File.WriteAllText("C:\\Users\\Donavon\\Desktop\\new.sql", text);

谢谢伙计。也谢谢其他的人,我从中学到了东西。感激大家。 - Donavon
@Donavon - 这种方法用大量的字符串拼接实在太糟糕了!请看我的答案,这是正确的做法。 - Trevor Pilley
2
@TrevorPilley:有无数种方法可以做到这一点。我可以说你的方法只是另一种方法;鉴于所有未知因素,称之为“正确”的确有些牵强。 - Brad Christie

3

这里没有代码解决方案,但是如果我必须做这样的事情并且我知道字符的位置始终相同(就像你的例子一样),我会选择使用Notepad++进行快速编辑,而不要去学习编程语言。

  1. 将光标放在''之间,并使用快捷键ALT+C

  2. 选择“插入数字”选项,填写初始数值(1)和增加数值(1)


3
   var lines = File.ReadAllLines(@"D:\temp\old.sql");

    for (int i = 0; i < lines.Count(); ++i)
         lines[i] = lines[i].Replace("\'\'", string.Format("\'{0}\'", i + 1));

    File.WriteAllLines(@"D:\temp\new.sql", lines);

0
string text = File.ReadAllText("old.sql");
text = text.Replace("some text", "new value");
File.WriteAllText("old.sql", text);

0

我认为这会起作用。大部分内容来自MSDN

  int counter = 1;
        string line;

        // Read the file and display it line by line.
        System.IO.StreamReader file = 
           new System.IO.StreamReader("C:\\Users\\Donavon\\Desktop\\old.sql");

        while((line = file.ReadLine()) != null)
        {
           line.Replace("('',", "('" + counter.ToString() + "',");;
           counter++;
        }

如何将该值写回新文件中? - Trevor Pilley

0

string text = File.ReadAllText("C:\Users\person\Desktop\old.sql"); System.Text.StringBuilder strBuilder = new StringBuilder();

字符串文本= File.ReadAllText("C:\Users\person\Desktop\old.sql"); 系统.Text.StringBuilder strBuilder = new StringBuilder();

        int i = 0;

        var theSplotStr = text.Split('\n');

        foreach (var item in theSplotStr)
        {
            System.Console.WriteLine(item);
            string revisedString = item.Replace("''", "'" + ++i + "'");
            strBuilder.Append(revisedString+"\n");

        }

        File.WriteAllText("C:\\Users\\person\\Desktop\\new.sql", strBuilder.ToString());

0

这里有一把锤子供你用来将图钉推入板子中...

如果你感兴趣,你可以通过并行操作更快地执行此操作。启动一个任务从旧文件中读取行,多个处理器任务清理读者任务读取的行,一个编写者任务将结果写回磁盘。

在我的 8 核机器上,我能够在不到 3 秒的时间内使用 ~100% 的 CPU 处理 124MB 的文件。

下面附有完全注释的代码。

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;

namespace ConsoleApplication
{
    public static class Test
    {
        //The paths to read and write
        const string OldFilePath = @"C:\Users\Donavon\Desktop\old.sql";
        const string NewFilePath = @"C:\Users\Donavon\Desktop\new.sql";

        //The maximum number of lines we can read for parallel processing
        //given the memory restrictions etc. Please set this to a number 
        //that is optimum for you.
        static readonly int ExpectedMaxLines = (int)Math.Pow(2, 10);

        //The data structures to hold the old and new lines
        private static readonly BlockingCollection<string> DirtyLines = new BlockingCollection<string>(ExpectedMaxLines);
        private static readonly BlockingCollection<string> CleanLines = new BlockingCollection<string>(ExpectedMaxLines);

        //A common factory. Since all tasks are long running, this is enough.
        private static readonly TaskFactory TaskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);

        public static void Main()
        {
            //Need to start one reader task which will read one line at a time and
            //put that line in the BlockingCollection for parallel processing.

            BeginReader();

            BeginParallelProcessing();

            //We have started 1 reader task and multiple processor tasks
            //Now we need to start a writer task that will write the cleaned lines to disk
            var finalTask = BeginWriter();

            //Since writer task is the task which will signify the end of the entire 
            //exercise of reading, processing and writing, we will wait till the 
            //writer task has finished too.
            Task.WaitAll(new[] {finalTask});

            Console.WriteLine("All text lines cleaned and written to disk.");
        }

        private static void BeginReader()
        {
            TaskFactory.StartNew(() =>
            {
                Console.WriteLine("Reader task initiated.");
                using (var reader = new StreamReader(OldFilePath))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        DirtyLines.TryAdd(line);
                    }
                    DirtyLines.CompleteAdding();
                }
            });
        }

        private static void BeginParallelProcessing()
        {
            //Starting as many processor tasks as there are number of processors available
            //on this machine. These tasks will return when there are no more lines to process

            //Globally defined id, and a lock, for adding in the required lines.
            var globalId = 1;
            var idLock = new object();

            for (var taskIndex = 0; taskIndex < Environment.ProcessorCount; taskIndex++)
            {
                TaskFactory.StartNew(() =>
                {
                    while (!DirtyLines.IsCompleted)
                    {
                        string line, updatedLine;
                        if (!DirtyLines.TryTake(out line)) continue;
                        if (line.Contains("(''"))
                        {
                            int nextGlobalId;
                            lock (idLock)
                            {
                                nextGlobalId = globalId++;
                            }
                            updatedLine = line.Replace("('',", "('" + nextGlobalId + "',");
                        }
                        else
                        {
                            updatedLine = line;
                        }
                        CleanLines.Add(updatedLine);
                    }
                    //Adding a delay of 10 seconds to allow all processing tasks to finish
                    Task.Delay(10*1000);
                    if (!CleanLines.IsAddingCompleted)
                    {
                        CleanLines.CompleteAdding();
                    }
                });
            }
        }

        private static Task BeginWriter()
        {
            var finalTask = TaskFactory.StartNew(() =>
            {
                Console.WriteLine("Writer task initiated.");
                using (var writer = new StreamWriter(NewFilePath))
                {
                    while (!CleanLines.IsCompleted)
                    {
                        string cleanLine;
                        if (!CleanLines.TryTake(out cleanLine)) continue;
                        writer.WriteLine(cleanLine);
                    }
                }
            });
            return finalTask;
        }
    }
}

-1
// Read file in by line (give us an array to work with)
var file = File.ReadAllLines("old.sql");

// Write the lines back (after we've modified it through LINQ)
File.WriteAllLines("new.sql", file.Select((line,index) => {
  // Use the overload of `.Select()` which includes the index

  // Simple string replace at this point, inserting our index.
  return line.Replace("('',", String.Format("('{0}',", index));
}));

这甚至不能编译成C#,如果你打开一个大文件,ReadAllLines会让你感到沮丧! - Trevor Pilley
忘记了一个 .Select。是的,但是我想尝试另一种方法。 - Brad Christie
"old.sql" 也不行,你需要使用 'old.sql'。 - Trevor Pilley
天啊,好笑。在LINQPad里完全没问题,但翻译成代码后出了点问题。觉得这几天做太多JS/Angular了,已经有点困惑了。;-( - Brad Christie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接