从文本文件中读取一行,然后用新文本 C# 替换同一行

Posted

技术标签:

【中文标题】从文本文件中读取一行,然后用新文本 C# 替换同一行【英文标题】:Reading a line from a text file and then replacing the same line with new text C# 【发布时间】:2020-08-11 17:58:21 【问题描述】:

我试图弄清楚如何在通过 ID 搜索文本文件后替换它,然后编写新信息来替换它。它适用于客户管理系统,此特定方法是通过 ID 搜索客户,返回搜索到的信息,然后修改相同的信息以将其写回。保存信息的 CSV 设置如下:

[ID][Title][firstName][lastName][Gender][DOB]

[0][Mrs][Jane][Doe][Female][1/1/1990]

[1][先生][John][Doe][Male][1/1/1991]

[2][Ms][Sarah][Doe][Female][1/1/2010]

我有一种感觉 StreamWriter 使用不正确,因为我可以把所有东西都放进去,当我把断点放进去调试时,作者在底部把它全部捡起来,但是一旦我按下回车,什么都没有发生数据就消失了。或者我可能没有在正确的位置收集用户输入。我已经对代码进行了格式化,以便于获取和调试:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication1

    class Program
    
        public class Customer
        
            public int ID  get; set; 
            public string Title  get; set; 
            public string FirstName  get; set; 
            public string LastName  get; set; 
            public string Gender  get; set; 
            public DateTime DOB  get; set; 
        

        static void Main(string[] args)
        
            const char DELIM = ',';
            const int END = 0;
            const string FILENAME = "D:\\customers.csv";
             FileStream inFile = new FileStream(FILENAME, FileMode.Open, FileAccess.ReadWrite);
             StreamWriter writer = new StreamWriter(inFile);
            
                while (true)
                
                    Console.WriteLine("  **Type " + END + " To Quit** Enter Customer ID Number> ");
                    var ID = Convert.ToInt32(Console.ReadLine());
                    if (ID == END) break;
                    inFile.Position = 0;
                    Console.WriteLine("0,51,102,153,154,155,25\n", "ID", "Title", "First Name", "Last Name", "Gender", "DOB");
                            foreach (var customer in GetCustomers(inFile, DELIM).Where(x => x.ID == ID))
                    
                        Console.WriteLine("0,51,102,153,154,155,25\n", customer.ID, customer.Title, customer.FirstName, customer.LastName, customer.Gender, customer.DOB);
                                Write("  Title> ");
                                customer.Title = ReadLine();
                                Write("  First Name> ");
                                customer.FirstName = ReadLine();
                                Write("  Last Name> ");
                                customer.LastName = ReadLine();
                                Write("  Gender> ");
                                customer.Gender = ReadLine();
                                Write("  Date Of Birth> ");
                                customer.DOB = Convert.ToDateTime(ReadLine());
                                writer.WriteLine(customer.ID + DELIM + customer.Title + DELIM + customer.FirstName + DELIM + customer.LastName + DELIM + customer.Gender + DELIM + customer.DOB);
                    
                
                        writer.Close();
                        inFile.Close();
            
        

        static IEnumerable<Customer> GetCustomers(Stream input, char separator)
        
            using (var reader = new StreamReader(input))
            
                // read header
                reader.ReadLine();

                while (true)
                
                    var line = reader.ReadLine();
                    if (line == null) yield break;
                    var fields = line.Split(separator);
                    yield return new Customer
                    
                        ID = Convert.ToInt32(fields[0]),
                        Title = fields[1],
                        FirstName = fields[2],
                        LastName = fields[3],
                        Gender = fields[4],
                        DOB = Convert.ToDateTime(fields[5])
                    ;
                
            
        
    


任何帮助将不胜感激

【问题讨论】:

写入非结构化文件不是一个好主意,而其内容仍在被读取。您正在使用读取器和写入器访问同一流。流的当前位置(用于读/写)将受到写入器和读取器的影响。结果出乎意料。 【参考方案1】:

首先,您确实不应该在接受用户输入的同时写入文件。您应该读取数据、更新数据,然后保存数据。不要混淆它们。

接下来,不要共享流。

我会这样做:

static IEnumerable<Customer> GetCustomers(string file, char separator)

    return
        from line in File.ReadLines(file).Skip(1)
        let fields = line.Split(separator)
        select new Customer()
        
            ID = Convert.ToInt32(fields[0]),
            Title = fields[1],
            FirstName = fields[2],
            LastName = fields[3],
            Gender = fields[4],
            DOB = Convert.ToDateTime(fields[5])
        ;


static void SaveCustomers(string file, char separator, string[] headers, IEnumerable<Customer> customers)

    IEnumerable<string[]> parts =
        from c in customers
        select new []
        
            c.ID.ToString(),
            c.Title,
            c.FirstName,
            c.LastName,
            c.Gender,
            c.DOB.ToShortDateString()
        ;

    IEnumerable<string> lines =
        from ps in new []  headers .Concat(parts)
        select String.Join(separator.ToString(), ps);

    File.WriteAllLines(file, lines);


static void Main(string[] args)

    const char DELIM = ',';
    const int END = 0;
    const string FILENAME = "D:\\customer.csv";

    string[] headers = new []  "ID", "Title", "First Name", "Last Name", "Gender", "DOB" ;

    List<Customer> customers = GetCustomers(FILENAME, DELIM).ToList(); //Must call `.ToList()` to force reading the file.

    var ID = -1;
    while (ID != 0)
    
        Console.WriteLine("  **Type " + END + " To Quit** Enter Customer ID Number> ");
        ID = Convert.ToInt32(Console.ReadLine());
        Console.WriteLine("0,51,102,153,154,155,25\n", headers);
        foreach (var customer in customers.Where(x => x.ID == ID))
        
            Console.WriteLine("0,51,102,153,154,155,25\n", customer.ID, customer.Title, customer.FirstName, customer.LastName, customer.Gender, customer.DOB);
            Console.Write("  Title> ");
            customer.Title = Console.ReadLine();
            Console.Write("  First Name> ");
            customer.FirstName = Console.ReadLine();
            Console.Write("  Last Name> ");
            customer.LastName = Console.ReadLine();
            Console.Write("  Gender> ");
            customer.Gender = Console.ReadLine();
            Console.Write("  Date Of Birth> ");
            customer.DOB = Convert.ToDateTime(Console.ReadLine());
        
    

    // Always save to a temporary file & then swap.

    var saveFileName = FILENAME.Replace(".csv", ".csv-temp");

    if (File.Exists(saveFileName))
    
        File.Delete(saveFileName);
    

    SaveCustomers(saveFileName, DELIM, headers, customers);

    if (File.Exists(saveFileName) && File.Exists(FILENAME))
    
        File.Delete(FILENAME);
        File.Move(saveFileName, FILENAME);
    

【讨论】:

以上是关于从文本文件中读取一行,然后用新文本 C# 替换同一行的主要内容,如果未能解决你的问题,请参考以下文章

c#写对象来读取TXT文本文件

在java中如何修改文本文件中的某一行的某些数据??

Rails 6:使用 Channel Stream 更新 Html,用新文本替换文本

在文本文件中搜索和替换字符串

从文本文件读取,然后写入 QT 中的同一文件(高分功能)

C# 文件流 streamreader如何读取文本指定行的数据?