0

I'm really getting stuck on how to design my program, in simple term, it needs to create a list of file in a given path and then sorts them for now by date creating the respective subdirectory. The problem arises since the files are uploaded by the phone in a NAS and their creation date gets modified when uploaded to this drive. Since we are talking about photos-video or audio I tried using metadata and the best way I found to retrieve some common date stored in the metadata based on this answer is this:

internal static class FileInSorting
{
    private static List<string> arrHeaders;
    private static List<int> date = new List<int>() { 197, 3, 4, 5, 12, 198, 287, 208 };
    private static List<FileToSort> fileToSort = new List<FileToSort>();

    public static List<FileToSort>  GetFilesToSort(string path)
    {
        Folder objFolder;
        LoadHeader(path, out arrHeaders, out objFolder);

         //I search for each file inside his extended property for the true creation date
         //If none is found I default to what FileInfo thinks is right
        foreach (Shell32.FolderItem2 item in objFolder.Items())
        {
            List<DateTime> tmp = new List<DateTime>();
            DateTime SelectedDate;
            foreach (int h in date)
            {
                string l = objFolder.GetDetailsOf(item, h);
                if (!string.IsNullOrEmpty(l))
                {
                    string asAscii = Encoding.ASCII.GetString(
                        Encoding.Convert(
                            Encoding.UTF8,
                            Encoding.GetEncoding(
                                Encoding.ASCII.EncodingName,
                                new EncoderReplacementFallback(string.Empty),
                                new DecoderExceptionFallback()),
                            Encoding.UTF8.GetBytes(l)
                            )
                        );

                    tmp.Add(DateTime.Parse(asAscii.Substring(0, 11)));
                }
            }
            if (tmp.Count == 0)
                SelectedDate = File.GetCreationTime(item.Path);
            else
                SelectedDate = tmp.Min();
            fileToSort.Add(new FileToSort(item.Name, item.Path, SelectedDate));


        }
        return fileToSort;
    }
    public static void LoadHeader(string path, out List<string> arrHeaders, out Folder objFolder)
    {
        arrHeaders = new List<string>();
        Shell32.Shell shell = new Shell32.Shell();
        objFolder = shell.NameSpace(path);

        for (int i = 0; i < short.MaxValue; i++)
        {
            string header = objFolder.GetDetailsOf(null, i);
            if (!String.IsNullOrEmpty(header))
                arrHeaders.Add(header);
        }
    }
}

I made this class just for easy use during sort but it could be completely redundant

   public class FileToSort
    {
        public string nome { get; set; }
        public string path { get; set; }
        public DateTime sortDate { get; set; }
        public FileToSort(string nome,string path,DateTime data)
        {
            this.nome = nome;
            this.path = path;
            this.sortDate = data;
        }
    }

The problem using this COM object is that is slow and not so easy to handle(maybe I'm just not able to) and as turned out on another question of mine it's not thread-safe, blocking out the option for parallel operation on multiple folders after the first sort. For example, i'm first sorting all files in a tree structure "[YEAR]/[Month]/[Full date]" but then I would have to recreate the COM object for each "Full date" folder and sort those by type. I'm aware that after the first date sort I could start using Directory.EnumerateFile() for each of the newly created folders but I would like to see if there is a better way to "design" the code so it can be reused without writing 2 separate methods for the date sort and for the type sort, so is there a way to avoid using the Com object entirely?

Quick edit I forgot another why I'm searching for another solution:

this is a WPF application and I would really like to use a ListView binded with a single collection perhaps a FileInfo collection

Armach
  • 15
  • 1
  • 5
  • This is really not the way to do it, no offence :-) What information are you trying to gather from files exactly? – Simon Mourier Jun 06 '22 at 16:16
  • Raw photos have dates inside their extended properties i didn't find any easy solution tath doesn't require this Shell32 object. And so it all spiraled down from there i guess – Armach Jun 06 '22 at 22:18
  • Basically you can query for extended property of any Shell Item like what's shown here: https://stackoverflow.com/a/69368804/403671 but using something like "System.Photo.DateTaken". Not sure what is exactly the property you're after. Do you have such a photo somewhere I can check for its properties? – Simon Mourier Jun 07 '22 at 05:37
  • I do not have any to easily link you, but I'm talking about raw photos or photo taken on a cellphone where there is all sort of tag the `List date` is just a series of index I found looking at the debug, I didn't have a clue System.Photo.DateTakenexisted ill might check it out it could probably return the same date I'm searching for in the extended properties – Armach Jun 07 '22 at 06:36
  • 1
    The code you're using is using the Shell columns, which is not exactly the same as properties. Columns are bound to Windows properties (and their index can vary per machine or Windows version), but properties can exist and be read w/o any UI concept. You should post some sample images somewhere on the Internet, it would be much easier to check. – Simon Mourier Jun 07 '22 at 07:04
  • So you are suggesting trying to use the exif? I was a bit skeptical on those because they vary from extension like jpeg to png – Armach Jun 07 '22 at 07:29
  • 1
    There's no magic here. If you're looking for image metadata, then well... it's image metadata. Windows properties (and columns) use all sort of ways to get the information, but it's still image metadata, if that's what you want. – Simon Mourier Jun 07 '22 at 07:35
  • yhea you are right... plus it may not spiral into this madness again. I'll totally give it a try thank you – Armach Jun 07 '22 at 07:39

1 Answers1

0

The problem arises since the files are in a network and their creation date gets modified when uploaded

That's your choice, and thus your problem. If you don't want file dates to change on upload, don't change them. Windows Explorer, for example, doesn't change them by default, you get the same creation date as the source. Your own code has full access over what dates to use.

I made this class just for easy use during sort but it could be completely redundant

You should look up record. And proper .Net naming conventions (public properties should be capitalized).

it's not thread-safe, blocking out the option for parallel operation on multiple folders after the first sort

You're jumping to assumptions here. It may not be thread-safe, but nothing stops you from creating multiple objects to query through, one for each thread. Look up thread-local variables and/or statics.

but then I would have to recreate the COM object for each "Full date" folder and sort those by type

That line is a little harder to understand, but if you're saying you "need" to requery the entire filesystem again just to sort items then you're dead wrong. Sorting is a view operation, the model doesn't care about it, and what you're writing here is the model. Sorting for the view can be handled any way you want, you have the data in memory already, sort as you wish.

And I don't wish to go through your code too deep, but holy wow what is this:

                string asAscii = Encoding.ASCII.GetString(
                    Encoding.Convert(
                        Encoding.UTF8,
                        Encoding.GetEncoding(
                            Encoding.ASCII.EncodingName,
                            new EncoderReplacementFallback(string.Empty),
                            new DecoderExceptionFallback()),
                        Encoding.UTF8.GetBytes(l)
                        )
                    );

If I had to rate it you'd be fired by the time I counted to 0... Just use the original string, what are you doing, man?

Blindy
  • 65,249
  • 10
  • 91
  • 131
  • For the Ascii part, I used the normal string but some of those dates have some strange charachter I could filter them all out, so I used this code to remove any stange charachter that DateTime could not parse. Im not sure what you are sayng about the View since the file get moved in the explorer. I do not change the date when i upload the photo in the NAS with his phone app it changes the creation date – Armach Jun 06 '22 at 15:26
  • XY problem. Fix whatever "strange characters" you find, don't do whatever madness this is. You're allocating more objects in what is presumably a tight loop than the entire data you get out of it. "with his phone app it changes the creation date" -- that's exactly my point, you chose to use that application, so it's your problem. It's not a property of a network file system that you lose file dates or whatever else you're claiming. – Blindy Jun 06 '22 at 15:29
  • For the rest like the convention etc.. I appreciate the sugegstion i will look them up even if this is just a "fun progect" for a quick tool i needed – Armach Jun 06 '22 at 15:30