Заменить значение и сохранить файл во время чтения файла CSV (C #) - PullRequest
0 голосов
/ 28 июня 2019

Я читаю CSV-файл:

string line;

StreamReader sr = new StreamReader(file.ToString());

while ((line = sr.ReadLine()) != null)
{
    string col1 = line.Split(',')[10]; //old value
    col1 = "my value"; //new value
}

sr.Close();
sr.Dispose();

Я хочу заменить старое значение новым.

Тогда мне нужно сохранить файл с изменениями.

Как я могу это сделать?

Ответы [ 2 ]

2 голосов
/ 28 июня 2019

Я предлагаю использовать File класс вместо Stream с и Reader с. Linq очень удобно при запросе данных:

var modifiedData = File
  .ReadLines(file.ToString())
  .Select(line => line.Split(',')) 
  .Select(items => {
     //TODO: put relevant logic here: given items we should return csv line
     items[10] = "my value";

     return string.Join(",", items);
   })
  .ToList(); // <- we have to store modified data in memory

File.WriteAllLines(file.ToString(), modifiedData);

Другая возможность (скажем, когда исходный файл слишком длинный, чтобы уместить в память) - сохранить измененные данные во временную файл , а затем Move это:

 var modifiedData = File
  .ReadLines(file.ToString())
  .Select(line => line.Split(',')) 
  .Select(items => {
     //TODO: put relevant logic here: given items we should return csv line
     items[10] = "my value";

     return string.Join(",", items);
   });

 string tempFile = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.tmp");

 File.WriteAllLines(tempFile, modifiedData);

 File.Delete(file.ToString());
 File.Move(tempFile, file.ToString());
0 голосов
/ 28 июня 2019

Чтение всего файла за один раз требует больших затрат памяти.Не говоря уже о создании его параллельной копии.Использование потоков может исправить это.Попробуйте это:

void Modify()
{
    using (var fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite))
    {
        string line;
        long position;

        while ((line = fs.ReadLine(out position)) != null)
        {
            var tmp = line.Split(',');
            tmp[1] = "00"; // new value
            var newLine = string.Join(",", tmp);
            fs.WriteLine(position, newLine);
        }
    }
}

с расширениями:

static class FileStreamExtensions
{
    private static readonly char[] newLine = Environment.NewLine.ToCharArray();
    private static readonly int length = Environment.NewLine.Length;
    private static readonly char eof = '\uFFFF';

    public static string ReadLine(this FileStream fs, out long position)
    {
        position = fs.Position;
        var chars = new List<char>();
        char c;
        while ((c = (char)fs.ReadByte()) != eof && (chars.Count < length || !chars.Skip(chars.Count - 2).SequenceEqual(newLine)))
        {
            chars.Add(c);
        }
        fs.Position--;

        if (chars.Count == 0)
            return null;

        return new string(chars.ToArray());
    }

    public static void WriteLine(this FileStream fs, long position, string line)
    {
        var bytes = line.ToCharArray().Concat(newLine).Select(c => (byte)c).ToArray();
        fs.Position = position;
        fs.Write(bytes, 0, bytes.Length);
    }
}

Недостатком является то, что вы должны сохранять свои значения одинаковой длины.Например, 999 и __9 имеют длину 3. Исправление делает все намного сложнее, поэтому я бы оставил это так.

Полный рабочий пример

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...