chu*_*gan 8 .net filenames path
我有一个固定长度的字段我想显示路径信息.我想在.NET中有一种方法可以通过插入省略号来缩写长路径名以适应固定长度字段,例如".....\myfile.txt的".我不能为我的生活找到这种方法.
Sam*_*Sam 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;
}
Run Code Online (Sandbox Code Playgroud)
重要说明: 传入格式化选项TextFormatFlags.ModifyString实际上会导致该MeasureText方法将字符串argument(compactedString)更改为压缩字符串.这看起来很奇怪,因为没有指定显式ref或out方法参数关键字,字符串是不可变的.但绝对是这样的.我假设字符串的指针通过不安全的代码更新为新的压缩字符串.
作为另一个出租人注意,因为我希望压缩字符串压缩路径,我也使用TextFormatFlags.PathEllipsis格式化选项.
我发现在控件上创建一个小的扩展方法很方便,所以任何控件(如TextBox和Label)都可以将它们的文本设置为压缩路径:
public static void SetTextAsCompactedPath(this Control control, string path)
{
control.Text = GetCompactedString(path, control.Font, control.Width);
}
Run Code Online (Sandbox Code Playgroud)
有紧凑路径的本土解决方案以及可以使用的一些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();
}
Run Code Online (Sandbox Code Playgroud)
还有更多的解决方案,包括正则表达式和路径的智能解析,以确定在哪里放置省略号.这些是我看到的一些:
如果有人在寻找相同的东西.我煮了这个功能:
/// <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;
}
Run Code Online (Sandbox Code Playgroud)
我不知道有一种方法可以自动执行此操作,但您可以轻松创建一个使用 Substring() 和 LastIndexOf("\") 或 System.IO.Path.GetFileName() 方法来仅获取文件名的方法,然后在前面加上你的点。