-4

I know there are a lot of similar topics on this website, but I think that I went through most of them and still cannot debug this piece of code. I really need to get this working. I'm newbie to C# and programming. Tho, I did this same assignment in Java, but for some reason, I can't make it work here. If some could please pitch in...

So I have some objects, which I am keeping in .txt file, one line = data for one object. First data of the line is an Id of an object, primary key basically. Right now I am implementing CRUD operations, that is, an Update. This edit function is supposed to contribute to that functionality.

If a user edit some of the selected object properties, that change needs to be reflected in .txt file. So, I will go through every object/line in the file, write them to some temp.txt file, once I hit object which has same Id as the passed object o, that means I need to write that edited object to temp.txt. After that I need to rename temp.txt to original file and delete temp.txt.

I have tried bunch of options and combinations, but none worked.

I really make sure that GetTxtPath returns correct absolute path from within my project.

Version 1:

public static void edit(Transformable o, string fileName)
{
    try
    {
        if (!File.Exists(FileUtils.GetTxtPath("temp.txt")))
        {
            File.Create(FileUtils.GetTxtPath("temp.txt"));
        }
        using (FileStream stream = File.OpenRead(FileUtils.GetTxtPath(fileName)))
        using (FileStream writeStream = File.OpenWrite(FileUtils.GetTxtPath("temp.txt")))
        {
            StreamReader reader = new StreamReader(stream);
            StreamWriter writer = new StreamWriter(writeStream);

            String line;
            while ((line = reader.ReadLine()) != null)
            {
                if (!line.Equals(""))
                {
                    if (o.GetId() == getIdFromString(line))
                    {
                        writer.Write(o.WriteToFile());
                    }
                    else
                    {
                        writer.Write(line + "\n");
                    }
                }
                else
                {
                    continue;
                }
            }
        }
    }
    catch (FileNotFoundException e)
    {
        Console.WriteLine($"The file was not found: '{e}'");
    }
    catch (DirectoryNotFoundException e)
    {
        Console.WriteLine($"The directory was not found: '{e}'");
    }
    catch (IOException e)
    {
        Console.WriteLine($"The file could not be opened: '{e}'");
    }
}

public static string GetTxtPath(string fileName)
{
    var startDirectory =
    Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;

    var absPath = startDirectory + @"\data\" + fileName;
    return absPath;
}

private static int getIdFromString(string line)
{
    return Int32.Parse(line.Split('|')[0]);
}

Version 2:

public static void Edit(Transformable o, string fileName)
{
    try
    {
        if (!File.Exists(FileUtils.GetTxtPath("temp.txt")))
        {
            File.Create(FileUtils.GetTxtPath("temp.txt"));
        }

        using (StreamReader reader = FileUtils.GetTxtReader(fileName))
        using (StreamWriter writer = FileUtils.GetTxtWriter("temp.txt"))
        {
            String line;
            while ((line = reader.ReadLine()) != null)
            {
                if (!line.Equals(""))
                {
                    if (o.GetId() == getIdFromString(line))
                    {
                        writer.Write(o.WriteToFile());
                    }
                    else
                    {
                        writer.Write(line + "\n");
                    }
                }
                else
                {
                    continue;
                }
            }
        }

        File.Move(FileUtils.GetTxtPath("temp.txt"), FileUtils.GetTxtPath(fileName));
        File.Delete(FileUtils.GetTxtPath("temp.txt"));
        //Here I tied many differenet options but nonthing worked

        //Here is Java code which did the job of renaming and deleting
        //------------------------------------------------------------
        //    File original = FileUtils.getFileForName(fileName);

        //    File backUpFile = new File("backUp");

        //    Files.move(original.toPath(), backUpFile.toPath(),
        //            StandardCopyOption.REPLACE_EXISTING);

        //    File temporary = FileUtils.getFileForName(temporaryFilePath);
        //    temporary.renameTo(original);
        //    backUpFile.delete();

        //    File original = FileUtils.getFileForName(path);
        //--------------------------------------------------------
        //public static File getFileForName(String name)
        //{

        //    String dir = System.getProperty("user.dir");
        //    String sP = System.getProperty("file.separator");
        //    File dirData = new File(dir + sP + "src" + sP + "data");

        //    File file = new File(dirData.getAbsolutePath() + sP + name);

        //    return file;

        //}
        //---------------------------------------------------------------------
    }
    catch (FileNotFoundException e)
    {
        Console.WriteLine($"The file was not found: '{e}'");
    }
    catch (DirectoryNotFoundException e)
    {
        Console.WriteLine($"The directory was not found: '{e}'");
    }
    catch (IOException e)
    {
        Console.WriteLine($"The file could not be opened: '{e}'");
    }




public static StreamReader GetTxtReader(string fileName)
{
    var fileStream = new FileStream(GetTxtPath(fileName), FileMode.Open, FileAccess.Read);
    return new StreamReader(fileStream, Encoding.UTF8);
}

public static StreamWriter GetTxtWriter(string fileName)
{
    FileStream fileStream = new FileStream(GetTxtPath(fileName), FileMode.Append);
    return new StreamWriter(fileStream, Encoding.UTF8);
}
Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49
Wrapper
  • 794
  • 10
  • 25
  • You state that … _”If a user edit some of the selected object properties?_ … HOW is the user doing this? It appears odd to write the crud operations to a “temporary” file. I would picture ALL the data from the original csv file being read into some collection type like a `List`. Then this `List` is displayed to the user through some UI like a `DataGridView.` Then after the user performs any crud operations on the UI, simply re-write the whole csv file from the `List`. Your approach appears to overcomplicate things. – JohnG Nov 10 '19 at 22:07
  • _but none worked_ - Specify what exactly does not work? Perhaps you have not been able to delete and rename the files because you did not release the resources (StreamReader/StreamWriter). – Alexander Petrov Nov 10 '19 at 22:32
  • Deleting a file then trying to move a temp file has many potential problems; breaking versions and metadata, deleting everything if the `Move` fails. Consult [Safe stream updates](https://stackoverflow.com/questions/324670/). – Dour High Arch Nov 11 '19 at 01:05

1 Answers1

0
public static void Edit(Transformable o, string fileName)
{
    try
    {
        string tempName = "temp.txt"; // create here correct path

        using (var readStream = File.OpenRead(fileName))
        using (var writeStream = File.OpenWrite(tempName))
        using (var reader = new StreamReader(readStream))
        using (var writer = new StreamWriter(writeStream))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                if (!line.Equals(""))
                {
                    if (o.GetId() == GetId(line))
                    {
                        writer.WriteLine(o.ToWriteableString());
                    }
                    else
                    {
                        writer.WriteLine(line);
                    }
                }
            }
        }

        File.Delete(fileName);
        File.Move(tempName, fileName);
    }
    catch ...

}

File.OpenWrite method opens an existing or creates a new file for writing. So there is no need to manually check and create the file.

You have wrapped FileStreams in a using statement quite correctly. However, StreamReader and StreamWriter also must to be released after use.

I renamed some methods, giving them names that conform to the naming rules in C#: Edit, GetId, ToWriteableString.

The else branch with the continue statement is not needed.

In the end, just use the File.Delete and File.Move methods.

Note: the int.Parse method can throw exceptions that also need to be handled.

Alexander Petrov
  • 13,457
  • 2
  • 20
  • 49