我有一个固定长度的字段我想显示路径信息。我想在.NET中有一种方法可以通过插入省略号来缩写长路径名以适应固定长度字段,例如“.. .... \ myfile.txt的”。我不能为我的生活找到这种方法。
答案 0 :(得分:17)
TextRenderer
。MeasureText
我遇到了与OP相同的困境,因为我需要一个解决方案来显示一条没有太多麻烦的缩写路径,以便我的UI可以轻松地显示路径的主要部分。最终解决方案:使用TextRenderer
的MeasureText
方法,如下所示:
public static string GetCompactedString(
string stringToCompact, Font font, int maxWidth)
{
// Copy the string passed in since this string will be
// modified in the TextRenderer's MeasureText method
string compactedString = string.Copy(stringToCompact);
var maxSize = new Size(maxWidth, 0);
var formattingOptions = TextFormatFlags.PathEllipsis
| TextFormatFlags.ModifyString;
TextRenderer.MeasureText(compactedString, font, maxSize, formattingOptions);
return compactedString;
}
重要说明:传递TextFormatFlags.ModifyString
格式化选项实际上会导致MeasureText
方法将字符串参数(compactedString
)更改为压缩字符串。这似乎很奇怪,因为没有指定明确的ref
或out
方法参数关键字,并且字符串是不可变的。但绝对是这样的。我假设字符串的指针通过不安全的代码更新为新的压缩字符串。
作为另一个出租人注意,由于我希望压缩字符串压缩路径,我还使用了TextFormatFlags.PathEllipsis
格式化选项。
我发现在控件上创建一个小扩展方法很方便,所以任何控件(如TextBox和Label)都可以将它们的文本设置为压缩路径:
public static void SetTextAsCompactedPath(this Control control, string path)
{
control.Text = GetCompactedString(path, control.Font, control.Width);
}
有紧凑型路径的本土解决方案以及可以使用的一些WinApi调用。
您可以使用pinvoke调用PathCompactPathEx
根据您希望限制的字符数压缩字符串。请注意,这不会考虑字体以及字符串在屏幕上显示的宽度。
代码来源PInvoke:http://www.pinvoke.net/default.aspx/shlwapi.pathcompactpathex
[DllImport("shlwapi.dll", CharSet=CharSet.Auto)]
static extern bool PathCompactPathEx(
[Out] StringBuilder pszOut, string szPath, int cchMax, int dwFlags);
public static string CompactPath(string longPathName, int wantedLength)
{
// NOTE: You need to create the builder with the
// required capacity before calling function.
// See http://msdn.microsoft.com/en-us/library/aa446536.aspx
StringBuilder sb = new StringBuilder(wantedLength + 1);
PathCompactPathEx(sb, longPathName, wantedLength + 1, 0);
return sb.ToString();
}
还有更多的解决方案,包括正则表达式和路径的智能解析,以确定放置省略号的位置。这些是我看到的一些:
答案 1 :(得分:6)
如果有人在寻找同样的事情。我把这个功能搞定了:
/// <summary>
/// Shortens a file path to the specified length
/// </summary>
/// <param name="path">The file path to shorten</param>
/// <param name="maxLength">The max length of the output path (including the ellipsis if inserted)</param>
/// <returns>The path with some of the middle directory paths replaced with an ellipsis (or the entire path if it is already shorter than maxLength)</returns>
/// <remarks>
/// Shortens the path by removing some of the "middle directories" in the path and inserting an ellipsis. If the filename and root path (drive letter or UNC server name) in itself exceeds the maxLength, the filename will be cut to fit.
/// UNC-paths and relative paths are also supported.
/// The inserted ellipsis is not a true ellipsis char, but a string of three dots.
/// </remarks>
/// <example>
/// ShortenPath(@"c:\websites\myproject\www_myproj\App_Data\themegafile.txt", 50)
/// Result: "c:\websites\myproject\...\App_Data\themegafile.txt"
///
/// ShortenPath(@"c:\websites\myproject\www_myproj\App_Data\theextremelylongfilename_morelength.txt", 30)
/// Result: "c:\...gfilename_morelength.txt"
///
/// ShortenPath(@"\\myserver\theshare\myproject\www_myproj\App_Data\theextremelylongfilename_morelength.txt", 30)
/// Result: "\\myserver\...e_morelength.txt"
///
/// ShortenPath(@"\\myserver\theshare\myproject\www_myproj\App_Data\themegafile.txt", 50)
/// Result: "\\myserver\theshare\...\App_Data\themegafile.txt"
///
/// ShortenPath(@"\\192.168.1.178\theshare\myproject\www_myproj\App_Data\themegafile.txt", 50)
/// Result: "\\192.168.1.178\theshare\...\themegafile.txt"
///
/// ShortenPath(@"\theshare\myproject\www_myproj\App_Data\", 30)
/// Result: "\theshare\...\App_Data\"
///
/// ShortenPath(@"\theshare\myproject\www_myproj\App_Data\themegafile.txt", 35)
/// Result: "\theshare\...\themegafile.txt"
/// </example>
public static string ShortenPath(string path, int maxLength)
{
string ellipsisChars = "...";
char dirSeperatorChar = Path.DirectorySeparatorChar;
string directorySeperator = dirSeperatorChar.ToString();
//simple guards
if (path.Length <= maxLength)
{
return path;
}
int ellipsisLength = ellipsisChars.Length;
if (maxLength <= ellipsisLength)
{
return ellipsisChars;
}
//alternate between taking a section from the start (firstPart) or the path and the end (lastPart)
bool isFirstPartsTurn = true; //drive letter has first priority, so start with that and see what else there is room for
//vars for accumulating the first and last parts of the final shortened path
string firstPart = "";
string lastPart = "";
//keeping track of how many first/last parts have already been added to the shortened path
int firstPartsUsed = 0;
int lastPartsUsed = 0;
string[] pathParts = path.Split(dirSeperatorChar);
for (int i = 0; i < pathParts.Length; i++)
{
if (isFirstPartsTurn)
{
string partToAdd = pathParts[firstPartsUsed] + directorySeperator;
if ((firstPart.Length + lastPart.Length + partToAdd.Length + ellipsisLength) > maxLength)
{
break;
}
firstPart = firstPart + partToAdd;
if (partToAdd == directorySeperator)
{
//this is most likely the first part of and UNC or relative path
//do not switch to lastpart, as these are not "true" directory seperators
//otherwise "\\myserver\theshare\outproject\www_project\file.txt" becomes "\\...\www_project\file.txt" instead of the intended "\\myserver\...\file.txt")
}
else
{
isFirstPartsTurn = false;
}
firstPartsUsed++;
}
else
{
int index = pathParts.Length - lastPartsUsed - 1; //-1 because of length vs. zero-based indexing
string partToAdd = directorySeperator + pathParts[index];
if ((firstPart.Length + lastPart.Length + partToAdd.Length + ellipsisLength) > maxLength)
{
break;
}
lastPart = partToAdd + lastPart;
if (partToAdd == directorySeperator)
{
//this is most likely the last part of a relative path (e.g. "\websites\myproject\www_myproj\App_Data\")
//do not proceed to processing firstPart yet
}
else
{
isFirstPartsTurn = true;
}
lastPartsUsed++;
}
}
if (lastPart == "")
{
//the filename (and root path) in itself was longer than maxLength, shorten it
lastPart = pathParts[pathParts.Length - 1];//"pathParts[pathParts.Length -1]" is the equivalent of "Path.GetFileName(pathToShorten)"
lastPart = lastPart.Substring(lastPart.Length + ellipsisLength + firstPart.Length - maxLength, maxLength - ellipsisLength - firstPart.Length);
}
return firstPart + ellipsisChars + lastPart;
}
答案 2 :(得分:4)
通过缩短长文件路径的Coding Horror blog post,您可以使用Windows API调用PathCompactPathEx
。
答案 3 :(得分:1)
您正在考虑StringTrimming.EllipsisPath
枚举常量,该常量可以与StringFormat
一起使用绘制使用Graphics.DrawString
修剪的路径。但是,.Net本身没有返回修剪路径的方法。
答案 4 :(得分:0)
我不知道自动执行此操作的方法,但您可以轻松创建一个iether使用Substring()和LastIndexOf(“\”)或System.IO.Path.GetFileName()方法来获取文件名,然后加上你的点。
答案 5 :(得分:0)
怎么样:
string longPath = @"c:\somewhere\myfile.txt";
string shortPath = @"..\" + Path.GetFileName(longPath);
答案 6 :(得分:0)
我发现了一个易于使用的类,它来自TextBox: EllipsisTextBox ,它封装了StringTrimming.EllipsisPath。适合我!