C# 函数可缩小文件路径,使其更易于阅读

C# 函数可缩小文件路径,使其更易于阅读,c#,.net,filepath,C#,.net,Filepath,在c#中是否有任何函数可以读取文件路径 输入:“c:\users\Windows\Downloaded Program Files\Folder\Inside\example\file.txt” 输出:“c:\users\…\example\file.txt”,对我来说,这看起来不像是人类可读的。无论如何,我认为没有这样的功能。在\字符上拆分它,只保留前两个插槽和最后两个插槽,就可以了 类似这样的代码,尽管代码不是很优雅 string[] splits = path.Split('\\');

在c#中是否有任何函数可以读取文件路径

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


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

,对我来说,这看起来不像是人类可读的。无论如何,我认为没有这样的功能。在\字符上拆分它,只保留前两个插槽和最后两个插槽,就可以了

类似这样的代码,尽管代码不是很优雅

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

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

TextRenderer.MeasureText(path, Font, 
    new System.Drawing.Size(Width, 0),
    TextFormatFlags.PathEllipsis | TextFormatFlags.ModifyString);
它将就地修改路径

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

string temp = String.Copy(path);

您可以使用以下内容:

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;
}
公共字符串收缩路径(字符串路径,int-maxLength)
{
列表部分=新列表(path.Split('\\');
字符串开始=部分[0]+@“\”+部分[1];
部分。移除(1);
部分。移除(0);
字符串结束=部分[parts.Count-1];
零件移除(零件计数-1);
部分。插入(0,“…”);
而(parts.Count>1&&
start.Length+end.Length+parts.Sum(p=>p.Length)+parts.Count>maxLength)
零件移除(零件计数-1);
字符串mid=“”;
parts.ForEach(p=>mid+=p+@“\”;
返回开始+中间+结束;
}
或者只使用奥利弗溶液,这更容易;-)

杰夫·阿特伍德(Jeff Atwood)在他的博客上提供了解决方案,如下所示:

[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();
}

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

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();
}

我正面临着这个问题,因为漫长的道路正在成为一个完全令人头疼的问题。这是我很快拼凑出来的东西(注意马虎),但它完成了工作

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;
}

编辑

以下是梅林2001年修正案的更新

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);
    }
    // result can be longer than maxLength
    return output.Substring(0, Math.Min(maxLength, output.Length));  
}

如果您想为这个问题编写自己的解决方案,请使用内置类,如:FileInfoDirectory等。。。这使得它不那么容易出错

下面的代码生成“VS样式”的缩短路径,如:“C:\…\Folder\File.ext”

公共静态类路径格式化程序
{
公共静态字符串收缩路径(字符串绝对路径、整数限制、字符串间隔符=“…”)
{
if(string.IsNullOrWhiteSpace(绝对路径))
{
返回字符串。空;
}
if(绝对路径长度限制)
{
打破
}
零件。插入(2,目录名称);
dir=dir.Parent;
ret=string.Join(“\\”,parts);
}
返回ret;
}
}

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

这是30个“W”字符:

wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww

以下是30个“i”字符:

IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII

如您所见,计数字符并不是真正有用的

而且不需要编写自己的代码,因为Windows API从Windows 95起就具有这一功能。 此功能的名称为“路径省略号”。 Windows API
DrawTextW()
有一个标志
DT\u PATH\u省略号
,它正好做到了这一点。 在.NET framwork中,
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 Designer中关闭
自动省略号
,并为标签指定固定宽度(路径应占据的最大宽度)

您甚至可以在VisualStudioDesigner中看到截断的路径

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

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

即使在Visual Studio Designer中,也会显示如下:


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”

如果(splits.Length>4),我还将添加一个
if
在那里也进行测试。这绝对不是缩小路径…考虑一下像
C:\veryveryylong\supersupersuperlong\a\b\C\d.txt这样的路径……您的解决方案将解决什么问题?这是针对WinForms还是只需要一个较短的字符串?(我这样问是因为.NET只支持绘图,它只适用于WinForms和图像)。为什么要删除完整路径?如果是这种情况,用户将无法找到文件。如果您对此不担心,则根本不显示路径,只显示文件名。user946874:不客气。另外,由于您是StackOverflow新手,我想通知您,您可以接受对您有帮助的答案最重要的是检查答案旁边的勾号。奇怪的是,这在framework 3.5中运行得很好,我更新到vs 2010和framework 4,现在我在这一行中遇到了一个无法调试的崩溃。(visual studio正忙着…)切换到
CharSet.Ansi
“已解决”(?)这个问题。@v.oddou它对我来说也崩溃了,直到我看到哪个使用了另一个常量
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;
}
String s_Text = @"C:\WINDOWS\Installer{40BF1E83-20EB-11D8-97C5-0009C5020658}\ARPPRODUCTICON.exe";
s_Text = ShortenPath(s_Text, new Font("Arial", 12), 500);