获取可执行文件当前位置的路径

Getting the path of the executable file's current location

我有一个非常简单的应用程序,它会自动从 Git 标签中获取固件文件的版本号,并将固件版本写入二进制文件的末尾并将版本附加到名称中每次我构建固件文件。对于我从事的每个项目,我都想将此可执行文件复制到固件的项目文件夹中,因此该应用程序只需在其所在的同一目录中查找所需的文件,而不管它的实际位置(因此我不每次都必须重新编程)。

这在 VS 项目文件夹中运行良好(我复制了所需的文件),但是当我将 .exe 文件移动到固件项目文件夹时它不再运行。我认为问题是获取 .exe 位置路径的代码仍然是它自己的项目文件夹,而不是新位置。让它工作的正确方法是什么?

我试过:

Environment.CurrentDirectory;
Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
System.Reflection.Assembly.GetExecutingAssembly().Location;

和其他一些人。我不明白为什么这必须是一件如此困难的事情。

编辑:.Net Core3.1

编辑:完整代码:

using System;
using System.IO;
using System.Diagnostics;

namespace VersionAppend
{ 
    class Program
    {
        const int INSERT_OFFSET = 0x1EFF9;
        const byte VER_NUMS = 3;
        const byte VER_SIZE = VER_NUMS * sizeof(ushort);

        static void Main(string[] args)
        {
            byte[] version = new byte[VER_SIZE];
            string versionFileName = AppContext.BaseDirectory + @"\version";

            if (!File.Exists(versionFileName))
            {
                Trace.WriteLine("Error");
                return;
            }

            // Get Firmware version as string
            string versionString = File.ReadAllText(versionFileName);

            // Break version into parts
            Version ver = Version.Parse(versionString);

            convertVersionToBytes(ver, version);

            // Search for Firmware File
            string directory = AppContext.BaseDirectory + @"\Debug";
            string firmwareKeyword = "firmware";

            var files = Directory.EnumerateFiles(directory, "*" + firmwareKeyword + ".bin");

            foreach (string item in files)
            {
                // Open firmware file
                BinaryWriter firmware = new BinaryWriter(new FileStream(item, FileMode.Open));

                firmware.Seek(INSERT_OFFSET, SeekOrigin.Begin);
                // Write version to end
                firmware.Write(version, 0, (int)VER_SIZE);

                // Close firmware file
                firmware.Close();

                string extension = Path.GetExtension(item);

                string file = Path.GetFileNameWithoutExtension(item);

                // Rename file with version
                string verString = convertVersionToString(version);
                File.Move(item, @item.Substring(0, item.Length -extension.Length) + "_" + verString + ".bin");
            }
               
        }

        private static void convertVersionToBytes (Version ver, byte [] version)
        {
            // Major.MSB, Major LSB, Minor...
            version[0] = (byte)((ushort)(ver.Major >> 8) & 0xFF);
            version[1] = (byte)((ushort)ver.Major & 0xFF);
            version[2] = (byte)((ushort)(ver.Minor >> 8) & 0xFF);
            version[3] = (byte)((ushort)ver.Minor & 0xFF);
            version[4] = (byte)((ushort)(ver.Build >> 8) & 0xFF);
            version[5] = (byte)((ushort)ver.Build & 0xFF);
        }

        private static string convertVersionToString(byte [] version)
        {
            return BitConverter.ToString(version).Replace("-", "");
        }

    }
}

不难。

但它 可能 取决于您的目标平台(您尚未指定)。

对于 .Net Core 1.x 和 .Net 5 或更高版本,我会使用 AppContext.BaseDirectory

以下是多年来针对各种环境的一些其他替代方案:

6 ways to get the current directory in C#, August 17, 2010

  • AppDomain.CurrentDomain.BaseDirectory This is the best option all round. It will give you the base directory for class libraries, including those in ASP.NET applications.

  • Directory.GetCurrentDirectory() Note: in .NET Core this is the current best practice. The details below relate to the .NET Framework 4.5 and below.

    This does an interop call using the winapi GetCurrentDirectory call inside kernel32.dll, which means the launching process’ folder will often be returned. Also as the MSDN documents say, it’s not guaranteed to work on mobile devices.

  • Environment.CurrentDirectory
    This simply calls Directory.GetCurrentDirectory()

  • Assembly.Location
    This would be called using

    this.GetType().Assembly.Location

    This returns the full path to the calling assembly, including the assembly name itself. If you are calling a separate class library, then its base directory will be returned, such “C:\myassembly.dll” - depending obviously on which Assembly instance is being used.

  • Application.StartupPath
    This is inside the System.Windows.Forms namespace, so is typically used in window forms application only.

  • Application.ExecutablePath The same as Application.StartupPath, however this also includes the application name, such as “myapp.exe”