0

I have a c# application that connects to a server, gets the datagrid, manipulates each row and then according to each updated row the new row gets uploaded to the server and one file per row gets renamed on the hdd.

The application works totally fine but i analyzed it with the profiler and realised that this line of code:

File.Move(symbolsOldPath, symbolsPath); 

takes 80% of the time my application needs to complete its task.

I went through all the questions on StackOverflow and other questions out there if there is a different way for a better performance but i wasnt succesful. The only other way i found was implementing VB to use the Rename method, but as it calls the File.Move method it is no improvement. Do you guys know an alternative way with better performance?

Here is my code of the class that changes the data.

    public DataTable ChangeData(DataTable unchangedData, string searchPathSymbols, string searchPathImages, ProgressBar pbForm)
    {
        pbtemp = pbForm;
        int rowCount = unchangedData.Rows.Count;

        foreach (DataRow row in unchangedData.Rows)
        {
            counter++;

            if (counter == 10)
            {
                pbtemp.Value += counter;
                counter = 0;
                Application.DoEvents();
            }

            number = row[1].ToString();
            symbolsPath = row[2].ToString();
            symbolsPathCopy = symbolsPath;
            imagesPath = row[3].ToString();
            imagesPathCopy = imagesPath;

            aliasSymbols = symbolsPath.Substring(0, symbolsPath.IndexOf('>') + 1);

            if (symbolsPath == imagesPath)
            {
                if (aliasSymbols.Contains("Symbole"))
                {
                    if (!string.IsNullOrEmpty(symbolsPath))
                    {
                        SymbolsChanger(searchPathSymbols, row);
                        row[3] = row[2];
                    }
                }

                else
                {
                    if (!string.IsNullOrEmpty(imagesPath))
                    {
                        ImagesChanger(searchPathImages, row);
                        row[2] = row[3];
                    }
                }
            }

            else
            {
                if (!string.IsNullOrEmpty(symbolsPath))
                {
                    SymbolsChanger(searchPathSymbols, row);
                }

                if (!string.IsNullOrEmpty(imagesPath))
                {
                    ImagesChanger(searchPathImages, row);
                }
            }
        }
        pbtemp.Value += (rowCount - pbtemp.Value);
        return unchangedData;
    }

    private void SymbolsChanger(string searchPathSymbols, DataRow row)
    {
        string symbolsOldPath;
        //Symbols
        //Get and delete Alias and get filepath

        int countAliasSymbolsIndex = symbolsPath.LastIndexOf('>') + 1;
        symbolsPath = symbolsPath.Remove(0, countAliasSymbolsIndex);
        symbolsOldPath = searchPathSymbols + "\\" + symbolsPath;

        //Remove and replace numbers
        int startSymbolsIndex = 0;
        int endSymbolsIndex = symbolsPath.IndexOf('_') == -1 ? symbolsPath.LastIndexOf('.') : symbolsPath.IndexOf('_');
        int countSymbolsIndex = endSymbolsIndex - startSymbolsIndex;
        symbolsPath = symbolsPath.Remove(startSymbolsIndex, countSymbolsIndex);
        string nameSymbols = number + symbolsPath;
        symbolsPath = searchPathSymbols + "\\" + nameSymbols;

        try
        {
            //Rename file
            File.Move(symbolsOldPath, symbolsPath);             
        }
        catch(FileNotFoundException)
        {
            try
            {
                File.Move(symbolsPath, symbolsPath);
            }
            catch (FileNotFoundException)
            {
                logArrayDataChange.Add(symbolsPathCopy);
            }

        }

        row[2] = aliasSymbols + nameSymbols;
    }

    private void ImagesChanger(string searchPathImages, DataRow row)
    {
        string imagesOldPath;
        //Images
        //Get and delete Alias and get filepath
        string aliasImage = imagesPath.Substring(0, imagesPath.IndexOf('>') + 1);
        int countAliasImagesIndex = imagesPath.LastIndexOf('>') + 1;
        imagesPath = imagesPath.Remove(0, countAliasImagesIndex);
        imagesOldPath = imagesPath.StartsWith("\\") == true ? searchPathImages + imagesPath : searchPathImages + "\\" + imagesPath;

        //Remove and replace numbers
        int startImagesIndex = imagesPath.LastIndexOf("\\") == -1 ? 0 : imagesPath.LastIndexOf("\\");
        int endImagesIndex = imagesPath.IndexOf('_') == -1 ? imagesPath.LastIndexOf('.') : imagesPath.IndexOf('_');
        int countImagesIndex = endImagesIndex - startImagesIndex;
        imagesPath = imagesPath.Remove(startImagesIndex + 1, countImagesIndex - 1);

        int insertIndex = imagesPath.LastIndexOf("\\") == -1 ? 0 : imagesPath.LastIndexOf("\\");
        string nameImages = imagesPath.Insert(insertIndex + 1, number);
        imagesPath = searchPathImages + "\\" + nameImages;

        try
        {
            //Rename file
            File.Move(imagesOldPath, imagesPath);               
        }
        catch (FileNotFoundException)
        {
            try
            {
                File.Move(imagesPath, imagesPath);
            }
            catch (FileNotFoundException)
            {
                logArrayDataChange.Add(imagesPathCopy);
            }
        }

        row[3] = aliasImage + nameImages;
    }
}

}

L. Guthardt
  • 1,990
  • 6
  • 22
  • 44
  • 3
    File.Move is the way to do it – EpicKip Jul 10 '17 at 12:17
  • 1
    If it works fine whats the problem? If you analyse any code there will always be something that takes more time than anything else. – Alex K. Jul 10 '17 at 12:19
  • The way I see it is perfectly normal that renaming the file takes the longest, it is writing on the hard drive which is, by definition, quite slow. Anyhow, is the process taking very long? Unless you're renaming a ton of files should be quite fast anyhow, renaming a file is one of the quickest things to do on the file system. – Zalomon Jul 10 '17 at 12:20
  • This is a disk IO problem. You should invest in a faster disk. – Nasreddine Jul 10 '17 at 12:20
  • 1
    Don't get too hung up on the profiler % - The total time taken must equal 100%, so *something* has to take up a larger % of the time... – Alex Jul 10 '17 at 12:20
  • 1
    I know, but i am always curious about optimizing my code to get the most out of it. – L. Guthardt Jul 10 '17 at 12:21
  • 3
    How long does it take? – Derek Jul 10 '17 at 12:21
  • I would investigate the term `Premature Optimization` – Alex Jul 10 '17 at 12:21
  • @Nasreddine its a ssd so that should not be the problem and i just bought the new laptop. – L. Guthardt Jul 10 '17 at 12:22
  • Does https://stackoverflow.com/a/18987514/34092 help? – mjwills Jul 10 '17 at 12:23
  • @ Derek it takes about 500 seconds to rename those 13k files. – L. Guthardt Jul 10 '17 at 12:24
  • @mjwills It shouldn't. It uses [the same code as `File.Move`](http://referencesource.microsoft.com/#mscorlib/system/io/fileinfo.cs,465). – Patrick Hofman Jul 10 '17 at 12:24
  • @ mjwills thank you, i will try it out and update my question with the result. If i could upvote, i would do it. – L. Guthardt Jul 10 '17 at 12:25
  • You could try `Parallel.ForEach` on the collection/ – Alex Jul 10 '17 at 12:25
  • @PatrickHofman You may be right. https://msdn.microsoft.com/en-us/library/akth6b1k.aspx#Remarks does say there may be perf benefits in some contexts - whether they are useful in this specific context needs to be confirmed by L. Guthardt – mjwills Jul 10 '17 at 12:29
  • @mjwills The documentation only says something about multiple operations on the same file. That might be true since it then skips the checks. That doesn't seem particularly useful in this case. – Patrick Hofman Jul 10 '17 at 12:30
  • Possible duplicate of [Faster file move method other than File.Move](https://stackoverflow.com/questions/18968830/faster-file-move-method-other-than-file-move) – mjwills Jul 10 '17 at 12:32
  • @L.Guthardt Could you show us more of your code, in case that impacts options we can suggest to you? – mjwills Jul 10 '17 at 12:57

1 Answers1

4

I would keep File.Move to do the job. Besides a little overhead (checks), File.Move uses only the native MoveFile Windows call to move the file:

[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern bool MoveFile(String src, String dst);

You can call that method yourself, but I doubt it will get any faster than that.

From the documentation it seems that move is already built to rename efficiently:

The MoveFile function will move (rename) either a file or a directory ...

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325