缩小文件路径的功能更易于人类阅读

时间:2011-12-02 17:41:06

标签: c# .net filepath

c#中是否有任何函数来回显文件路径?

输入:“c:\ users \ Windows \ Downloaded Program Files \ Folder \ Inside \ example \ file.txt”

输出:“c:\ users \ ... \ example \ file.txt”

9 个答案:

答案 0 :(得分:6)

对我而言,这看起来不那么人性化。无论如何,我认为没有这样的功能。将它分开在\字符上,只保留前两个插槽和最后两个插槽即可。

这样的东西,虽然代码不是很优雅

  string[] splits = path.Split('\\');
  Console.WriteLine( splits[0] + "\\" + splits[1] + "\\...\\" + splits[splits.Length - 2] + "\\" +  splits[splits.Length - 1]);

答案 1 :(得分:5)

Nasreddine的答案几乎是正确的。 只需指定StringBuilder大小,在您的情况下:

[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
static extern bool PathCompactPathEx(
                       [Out] StringBuilder pszOut, 
                       string szPath, 
                       int cchMax, 
                       int dwFlags);

static string PathShortener(string path, int length)
{
    StringBuilder sb = new StringBuilder(length + 1);
    PathCompactPathEx(sb, path, length, 0);
    return sb.ToString();
}

答案 2 :(得分:3)

如果要根据路径字符串的长度插入省略号,请使用以下代码:

TextRenderer.MeasureText(path, Font, 
    new System.Drawing.Size(Width, 0),
    TextFormatFlags.PathEllipsis | TextFormatFlags.ModifyString);

它会就地修改path

编辑:请注意此方法。它打破了规则,说.NET中的字符串是不可变的。实际上,MeasureText方法的第一个参数不是ref参数,这意味着不能返回新的字符串。而是改变现有的字符串。处理使用

创建的副本时要小心
string temp = String.Copy(path);

答案 3 :(得分:3)

Jeff Atwood posted在他的博客上解决了这个问题,现在是:

[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
static extern bool PathCompactPathEx([Out] StringBuilder pszOut, string szPath, int cchMax, int dwFlags);

static string PathShortener(string path, int length)
{
    StringBuilder sb = new StringBuilder();
    PathCompactPathEx(sb, path, length, 0);
    return sb.ToString();
}

它使用非托管函数PathCompactPathEx来实现您想要的功能。

答案 4 :(得分:2)

您可以使用以下内容:

public string ShrinkPath(string path, int maxLength)
{
    List<string> parts = new List<string>(path.Split('\\'));

    string start = parts[0] + @"\" + parts[1];
    parts.RemoveAt(1);
    parts.RemoveAt(0);

    string end = parts[parts.Count-1];
    parts.RemoveAt(parts.Count-1);

    parts.Insert(0, "...");
    while(parts.Count > 1 && 
      start.Length + end.Length + parts.Sum(p=>p.Length) + parts.Count > maxLength)
        parts.RemoveAt(parts.Count-1);

    string mid = "";
    parts.ForEach(p => mid += p + @"\");

    return start+mid+end;
}

或者只使用Olivers解决方案,这更容易; - )。

答案 5 :(得分:1)

我刚刚面对这个问题,因为很长的路径正在成为一个完整的眼睛疼痛。这就是我快速拼凑在一起的东西(记住邋iness),但它完成了工作。

private string ShortenPath(string path, int maxLength)
{
    int pathLength = path.Length;

    string[] parts;
    parts = label1.Text.Split('\\');

    int startIndex = (parts.Length - 1) / 2;
    int index = startIndex;

    string output = "";
    output = String.Join("\\", parts, 0, parts.Length);

    decimal step = 0;
    int lean = 1;

    do
    {
        parts[index] = "...";

        output = String.Join("\\", parts, 0, parts.Length);

        step = step + 0.5M;
        lean = lean * -1;

        index = startIndex + ((int)step * lean);
    }
    while (output.Length >= maxLength && index != -1);

    return output;
}

Results

修改

以下是Merlin2001更正的更新。

private string ShortenPath(string path, int maxLength)
{
    int pathLength = path.Length;

    string[] parts;
    parts = path.Split('\\');

    int startIndex = (parts.Length - 1) / 2;
    int index = startIndex;

    String output = "";
    output = String.Join("\\", parts, 0, parts.Length);

    decimal step = 0;
    int lean = 1;

    while (output.Length >= maxLength && index != 0 && index != -1)
    {
        parts[index] = "...";

        output = String.Join("\\", parts, 0, parts.Length);

        step = step + 0.5M;
        lean = lean * -1;

        index = startIndex + ((int)step * lean);
    }

    return output;
}

答案 6 :(得分:1)

    private string ShrinkPath(string path, int maxLength)
    {
        var parts = path.Split('\\');
        var output = String.Join("\\", parts, 0, parts.Length);
        var endIndex = (parts.Length - 1);
        var startIndex = endIndex / 2;
        var index = startIndex;
        var step = 0;

        while (output.Length >= maxLength && index != 0 && index != endIndex)
        {
            parts[index] = "...";
            output = String.Join("\\", parts, 0, parts.Length);
            if (step >= 0) step++;
            step = (step * -1);
            index = startIndex + step;
        }
        return output;
    }

答案 7 :(得分:1)

如果要编写自己的解决方案,请使用诸如 FileInfo Directory 等之类的内建类,这样可以减少出错的可能性。

以下代码生成“ VS风格”的缩短路径,例如:“ C:\ ... \ Folder \ File.ext”。

public static class PathFormatter
{
    public static string ShrinkPath(string absolutePath, int limit, string spacer = "…")
    {
        if (string.IsNullOrWhiteSpace(absolutePath))
        {
            return string.Empty;
        }
        if (absolutePath.Length <= limit)
        {
            return absolutePath;
        }

        var parts = new List<string>();

        var fi = new FileInfo(absolutePath);
        string drive = Path.GetPathRoot(fi.FullName);

        parts.Add(drive.TrimEnd('\\'));
        parts.Add(spacer);
        parts.Add(fi.Name);

        var ret = string.Join("\\", parts);
        var dir = fi.Directory;

        while (ret.Length < limit && dir != null)
        {
            if (ret.Length + dir.Name.Length > limit)
            {
                break;
            }

            parts.Insert(2, dir.Name);

            dir = dir.Parent;
            ret = string.Join("\\", parts);
        }

        return ret;
    }
}

答案 8 :(得分:0)

这里几乎所有的答案都通过计算字符来缩短路径字符串。 但是这种方法忽略了每个字符的宽度。

这些是 30 个“W”字符:

WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW

这些是 30 个“i”字符:

iiiiiiiiiiiiiiiiiiiiiiiiiiiiii

如您所见,计算字符并不是很有用。

而且无需编写您自己的代码,因为 Windows API 自 Windows 95 起就具有此功能。 此功能的名称是“路径省略号”。 Windows API DrawTextW() 有一个标志 DT_PATH_ELLIPSIS 正是这样做的。 在 .NET 框架中,这在 TextRenderer 类中可用(无需使用 PInvoke)。

有两种使用方法:


1.) 将路径直接绘制到标签中:

public class PathLabel : Label
{
    protected override void OnPaint(PaintEventArgs e)
    {
        if (AutoSize)
            throw new Exception("You must set "+Name+".AutoSize = false in VS " 
                              + "Designer and assign a fix width to the PathLabel.");

        Color c_Fore = Enabled ? ForeColor : SystemColors.GrayText;
        TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, c_Fore, 
                              BackColor, TextFormatFlags.PathEllipsis);
    }
}

此标签要求您在 Visual Studio 设计器中关闭 AutoEllipsis 并为标签指定一个固定宽度(您的路径应占据的最大宽度)。

您甚至可以在 Visual Studio 设计器中看到被截断的路径。

我输入了一条不适合标签的长路径:

C:\WINDOWS\Installer{40BF1E83-20EB-11D8-97C5-0009C5020658}\ARPPRODUCTICON.exe

即使在 Visual Studio 设计器中,它也是这样显示的:

Label with Path Ellipsis in C#


2.) 缩短路径而不在屏幕上绘制:

public static String ShortenPath(String s_Path, Font i_Font, int s32_Width)
{
    TextRenderer.MeasureText(s_Path, i_Font, new Size(s32_Width, 100), 
                             TextFormatFlags.PathEllipsis | TextFormatFlags.ModifyString);

    // Windows inserts a '\0' character into the string instead of shortening the string
    int s32_Nul = s_Path.IndexOf((Char)0);
    if (s32_Nul > 0)
        s_Path = s_Path.Substring(0, s32_Nul);
    return s_Path;
}

标志 TextFormatFlags.ModifyString 在字符串中插入一个 '\0' 字符。在 C# 中修改字符串是非常不寻常的。 通常字符串是不可变的。 这是因为底层 API DrawTextW() 以这种方式工作。 但由于字符串只会缩短而永远不会变长,因此不存在缓冲区溢出的风险。

以下代码

String s_Text = @"C:\WINDOWS\Installer{40BF1E83-20EB-11D8-97C5-0009C5020658}\ARPPRODUCTICON.exe";
s_Text = ShortenPath(s_Text, new Font("Arial", 12), 500);

将导致“C:\WINDOWS\Installer{40BF1E83-20EB-1...\ARPPRODUCTICON.exe”