0

I want to count the number of some strings and store it into a csv file. I've tried it but I don't know if this is the correct way and in addition, there are two problems.

First of all, here is my method:

public void CountMacNames(String macName)
{
    string path = @"D:\Counter\macNameCounter.csv";

    if (!File.Exists(path))
    {
        File.Create(path).Close();
    }

    var lines = File.ReadLines(path);

    foreach (var line in lines)
    {
        bool isExists = line.Split(',').Any(x => x == macName);

        if (isExists)
        {
            // macName exists, increment it's value by 1
        }
        else
        {
            // macName does not exists, add macName to CSV file and start counter by 1
            var csv = new StringBuilder();
            var newLine = string.Format("{0},{1}", macName, 1);
            csv.AppendLine(newLine);
            File.WriteAllText(path, csv.ToString());
        }
    }
}

The first problem is this IOException:

The process cannot access the file 'D:\Counter\macNameCounter.csv' because it is being used by another process.

The second problem is, that I don't know how to increment the value by one, if a macName exists in the csv file (see first comment)

EDIT: Example for method "CountMacNames" call:

  • CountMacNames("Cansas");
  • CountMacNames("Wellback");
  • CountMacNames("Newton");
  • CountMacNames("Cansas");
  • CountMacNames("Princet");

Then, the CSV file should contain:

  • Cansas, 2
  • Wellback, 1
  • Newton, 1
  • Princet, 1
11
  • ad 1: if macNameCounter.csv is opened in other programs (f.e. notepad++), close it. Commented Apr 7, 2015 at 9:26
  • ad 2: macName sounds like 'a name'. what kind of name is it? give an example. Commented Apr 7, 2015 at 9:27
  • @stefankmitph it's not opened in other programs Commented Apr 7, 2015 at 9:27
  • 1
    You have the file open, with ReadLines so you can't write back to it, you haven't opened it with ReadWrite access. Commented Apr 7, 2015 at 9:30
  • 1
    var lines = File.ReadAllLines(path); (notice the All) closes the file handle after reading. You could try using that for files that are not unusually big (<100MB? If it get's bigger than that you should work with a DB anyways). Commented Apr 7, 2015 at 9:35

4 Answers 4

1

OK, this is what I'd do:

public void CountMacNames(String macName)
{
    string path = @"D:\Counter\macNameCounter.csv";

    // Read all lines, but only if file exists
    string[] lines = new string[0];
    if (File.Exists(path))
        lines = File.ReadAllLines(path);

    // This is the new CSV file
    StringBuilder newLines = new StringBuilder();
    bool macAdded = false;

    foreach (var line in lines)
    {
        string[] parts = line.Split(',');
        if (parts.Length == 2 && parts[0].Equals(macName))
        {
            int newCounter = Convert.ToIn32(parts[1])++;
            newLines.AppendLine(String.Format("{0},{1}", macName, newCounter));
            macAdded = true;
        }
        else
        {
            newLines.AppendLine(line.Trim());
        }
    }

    if (!macAdded)
    {
        newLines.AppendLine(String.Format("{0},{1}", macName, 1));
    }

    File.WriteAllText(path, newLines.ToString());
}

This code does this:

  1. Read all the lines from file only if it exists - otherwise we start a new file
  2. Iterate over all the lines
  3. If the first part of a 2-part line equals the mac, add 1 to counter and add line to output
  4. If the first part doesn't match or the line format is wrong, add the line to output as is
  5. If we didn't find the mac in any line, add a new line for the mac with counter 1
  6. Write the file back
Sign up to request clarification or add additional context in comments.

Comments

0

You can't read and write to the same file at the same time (in a simple way). For small files, there are already answers.

If your file is really large (too big to fit in memory) you need another approach:

  1. Read input file line by line
  2. optinally modify the current line
  3. write line to a temporary file
  4. If finished delete input file, rename temporary file

Comments

0

For the first problem you can either read all the lines into memory and work there then write it all out again, or use streams.

using (FileStream fs = File.Open(filePath, FileMode.Create, FileAccess.ReadWrite)) 
{
    var sw = new StreamWriter(fs);
    var sr = new StreamReader(fs);
    while(!streamReader.EndOfStream)
    {
        var line = sr.ReadLine();
        //Do stuff with line.
        //...
        if (macExists)
        {
           //Increment the number, Note that in here we can only replace characters,
           //We can't insert extra characters unless we rewrite the rest of the file
           //Probably more hassle than it's worth but
           //You could have a fixed number of characters like 000001 or     1

           //Read the number as a string,
           //Int.Parse to get the number
           //Increment it
           //work out the number of bytes in the line.
           //get the stream position
           //seek back to the beginning of the line
           //Overwrite the whole line with the same number of bytes.
        }
        else
        {
            //Append a line, also harder to do with streams like this.
            //Store the current position,
            //Seek to the end of the file,
            //WriteLine
            //Seek back again.
        }
    }
}

Comments

0

You need to read the file in and release it, like this, to avoid the IO exception:

 string[] lines = null;
 using (var sr = new System.IO.StreamReader(path))
    lines = sr.ReadToEnd().Split(new string[] {"\r", "\n"}, StringSplitOptions.RemoveEmptyEntries);

As for the count, you can just add an int value, change the method return type as int, too.

 public int CountMacNames(String macName, String path)
    {
        if (!File.Exists(path))
        {
            File.Create(path).Close();
        }

        string[] lines = null;
        using (var sr = new System.IO.StreamReader(path))
            lines = sr.ReadToEnd().Split(new string[] {"\r", "\n"}, StringSplitOptions.RemoveEmptyEntries);

        return lines.Where(p => p.Split(',').Contains(macName)).Count();
    }

and inside the method that calls it:

 var path = @"<PATH TO FILE>";
 var cnt = CountMacNames("Canvas", path);
 if (cnt > 0)
 {
     using (var sw = new StreamWriter(path, true, Encoding.Unicode))
          sw.WriteLine(string.Format("Canvas,{0}", cnt));
 }

Now, var res = CountMacNames("Canvas","PATH"); will return 2, and the lines "Canvas,2" or "Newton,1" will be appended to the file, without overwriting it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.