Bat, .Net и уровни каталогов

Рейтинг: 0Ответов: 1Опубликовано: 27.06.2023

Довольно-таки необычный вопрос, который завел меня в тупик. Итак - есть приложение написанное на C++ и есть приложение написанное на .Net 7. Дерево каталогов выглядит так:

Data\Run.bat
Data\Input\
Data\Output\
Data\Win64\Bin\App-C-plus.exe
Data\Win64\Bin\App-Dot-Net.exe

Содержимое .bat выглядит так:

@echo off

Data\Win64\Bin\App-C-plus.exe ..\..\Data\Input -build ..\..\Data\Output
Data\Win64\Bin\App-Dot-Net.exe ..\..\Data\Input -build ..\..\Data\Output

Содержимое приложения на .Net:

        static void Main(string[] args)
        {
            if (args.Length > 0) 
            { 
                if (args[1] == "-build")
                {
                    try
                    {
                        File.Copy(args[0], args[2], true);
                        Console.WriteLine($"File copied from {args[0]} to {args[1]}");
                    }

                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error: {ex.Message}");
                    }
                }
            }
        }

Вот мы и подобрались к сути вопроса: - почему данная команда в .bat файле для приложения написанного на .Net работает не так, как ожидалось:

Data\Win64\Bin\App-Dot-Net.exe ..\..\Data\Input -build ..\..\Data\Output

Но если изменить ее вот так:

Data\Win64\Bin\App-Dot-Net.exe Data\Input -build Data\Output

Чтобы получилось вот так:

@echo off

Data\Win64\Bin\App-C-plus.exe ..\..\Data\Input -build ..\..\Data\Output
Data\Win64\Bin\App-Dot-Net.exe Data\Input -build Data\Output

Все отлично работает. Причем команда для приложения написанного на C++ работает исправно. Мы можем спокойно перейти на уровень каталога выше. Я просто не понимаю, почему стандартная команда перехода на каталог выше, работает не так как я этого ожидал. Не то чтобы меня это беспокоит, просто не могу найти на это ответ. То есть приложение инициализирует запуск, как будто непосредственно находится в папке Data.

UPD: Добавил код, но вариант, предложенный товарищем @rotabor гениален, именно что-то такое я и предпологал:

Directory.SetCurrentDirectory(System.Reflection.Assembly.GetExecutingAssembly().Location);

Правда я его еще не протестировал, но думаю что это то, что нужно.

UPD-1: Протестировал, получаю это:

Error: The value cannot be an empty string. (Parameter 'path')

Код выглядит так:

        static void Main(string[] args)
        {
            if (args.Length > 0) 
            { 
                if (args.Length == 2)
                {
                    try
                    {
                        Directory.SetCurrentDirectory(System.Reflection.Assembly.GetExecutingAssembly().Location);
                        File.Copy(args[0], args[1], true);
                        Console.WriteLine($"File copied from {args[0]} to {args[1]}");
                    }

                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error: {ex.Message}");
                    }
                }
            }
        }

Ответы

▲ 1Принят

Секрет как раз и заключается в строке "//Copy file here {From source to Destination}", равно как и в соотвествующей строке приложения на С++, а вы их не показали. Похоже, что последнее работает от собственного каталога, а .NET - от каталога запуска. Ну и бибилиотеки System.IO и соотвествующая в С++ могут работать по-разному.

В общем, пока удивительного ничего нет.

Вы еще позапускайте батник из командной строки из разных папок, наверняка что-то пойдёт не так.

UPD В документации всё подробно расписано https://learn.microsoft.com/en-us/dotnet/api/system.io.path.getfullpath?view=net-7.0

Пример:

using System;
using System.IO;
namespace NsPathUncertanity {
    class PathUncertanity {
        static void Main(string[] args) {
            try {
                switch (args.Length) {
                    case 0: Console.WriteLine("nop"); break;
                    case 1: Console.WriteLine(Path.GetFullPath(args[0])); break;
                    // case 2: Console.WriteLine(Path.GetFullPath(args[0], args[1])); break;
                }
            }
            catch (Exception objException) { Console.WriteLine(objException.Message); }
        }
    }
}

Результат:

C:\Users\auser\Documents\My Projects\Stackoverflow>ar graf.txt
C:\Users\auser\Documents\My Projects\Stackoverflow\graf.txt

C:\Users\auser\Documents\My Projects\Stackoverflow>ar ..\drum.txt
C:\Users\auser\Documents\My Projects\drum.txt

C:\Users\auser\Documents\My Projects\Stackoverflow>ar ..\..\drum.txt
C:\Users\auser\Documents\drum.txt

Всё работает согласно документации. Возможно, вы где-то ранее меняете текущий путь, что влияет на интерпретацию ".."

UPD UPD Если вам нужно просто повторить то, что написано на С++, то используйте

Directory.SetCurrentDirectory(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));

перед File.Copy