C# приложение ищет System32 вместо локального файла - PullRequest
0 голосов
/ 07 апреля 2020

Я разработал приложение C# winforms. Для запуска приложения требуется другой файл, который находится в том же каталоге, что и исполняемый файл. Позволяет назвать этот файл a.abc. Когда я использую командную строку, перейдите в каталог программы и введите следующую команду, чтобы открыть файл с моей программой, он работает нормально:

my-prog.exe "path-to-file\file-name"

Однако, когда я щелкаю правой кнопкой мыши файл в проводнике, go чтобы открыть и выбрать мою программу, программа почему-то пытается найти файл a.abc в каталоге System32, а не в каталоге приложения.

enter image description here

Я знаю, что это будет работать нормально, если я использую полный путь к файлу вместо относительного пути, но мне интересно, почему это происходит?

ОБНОВЛЕНИЕ # 1

У меня есть строковый ресурс с именем reqdFileName со значением toolset.f

И я обращаюсь к файлу с помощью

using (StreamReader sr = File.OpenText(@Properties.Resources.reqdFileName))
    // read lines and use it here
}

1 Ответ

0 голосов
/ 08 апреля 2020

Это все о абсолютных и относительных путях . Поскольку ваш путь относительный, он «предварен» вашим рабочим каталогом .

Итак, когда вы запускаете свою программу в директории приложения (скажем, C:\MyProgram\) - путь a.abc равно C:\MyProgram\a.abc. Если вы запустите его из другого каталога (скажем, C:\), например: .\MyProgram\my-prog.exe, то путь a.abc будет равен C:\a.abc. Вы можете получить текущий рабочий каталог с помощью System.IO.Directory.GetCurrentDirectory() метода , чтобы проверить это самостоятельно.

Когда вы используете "Открыть с помощью" меню - ваш текущий каталог будет быть %windir%\system32 и это "by-design" , вы не должны пытаться изменить это.


Вы можете решить свою проблему, преобразовав относительный путь в абсолютный путь, например:

using System.Reflection;
using System.IO;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
var reqdFilePath = Path.Combine(appPath, @Properties.Resources.reqdFileName);
using (StreamReader sr = File.OpenText(reqdFilePath))
    // read lines and use it here
}

Другой вариант - изменить рабочий каталог где-то в начале вашей программы:

using System.Reflection;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
Directory.SetCurrentDirectory(appPath);
// we are in your app directory now for sure

// ... Later in your code ...
using (StreamReader sr = File.OpenText(@Properties.Resources.reqdFileName))
    // read lines and use it here
}

Однако в этом случае вам как-то нужно restore ваш рабочий каталог в конце вашей программы, потому что это будет разочаровывать ваших пользователей, если они будут принудительно перемещаться по какому-то пути в конце (я бы не хотел такую ​​программу, если вы спросите меня).

Там В некоторых комментариях также рекомендуется добавлять каталог приложения в переменную %PATH% evironment. Это поможет, но , пожалуйста , не загрязняйте ваш %PATH%, если вам это явно не нужно. %PATH% не безграничен - здесь - хорошее объяснение.


И просто примечание. Нет реальной необходимости иметь дело с потоками и программами чтения потоков для чтения файла построчно. Существует File.ReadAllLines() метод :

using System.Reflection;
using System.IO;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
var reqdFilePath = Path.Combine(appPath, @Properties.Resources.reqdFileName);
foreach (var line in File.ReadAllLines(reqdFilePath))
{
    // use your line here
}

Как я уже сказал, он будет читать его построчно , так что нормально читать огромное файл (он не будет загружать весь файл в вашу память, только одну строку за раз). Если ваш файл не такой большой, вы также можете прочитать его за один снимок за один string с File.ReadAllText() методом .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...