Fix file naming template on unix systems

This commit is contained in:
= 2022-12-29 14:12:46 -07:00
parent 83fb2cd1d0
commit 6901b8be35
2 changed files with 21 additions and 3 deletions

View File

@ -44,16 +44,34 @@ namespace FileManager
var fileNamePart = pathParts[^1]; var fileNamePart = pathParts[^1];
pathParts.Remove(fileNamePart); pathParts.Remove(fileNamePart);
var fileExtension = Path.GetExtension(fileNamePart);
fileNamePart = fileNamePart[..^fileExtension.Length];
LongPath directory = Path.Join(pathParts.Select(p => replaceFileName(p, paramReplacements, LongPath.MaxFilenameLength)).ToArray()); LongPath directory = Path.Join(pathParts.Select(p => replaceFileName(p, paramReplacements, LongPath.MaxFilenameLength)).ToArray());
//If file already exists, GetValidFilename will append " (n)" to the filename. //If file already exists, GetValidFilename will append " (n)" to the filename.
//This could cause the filename length to exceed MaxFilenameLength, so reduce //This could cause the filename length to exceed MaxFilenameLength, so reduce
//allowable filename length by 5 chars, allowing for up to 99 duplicates. //allowable filename length by 5 chars, allowing for up to 99 duplicates.
return FileUtility.GetValidFilename(Path.Join(directory, replaceFileName(fileNamePart, paramReplacements, LongPath.MaxFilenameLength - 5)), replacements, returnFirstExisting); return FileUtility
.GetValidFilename(
Path.Join(directory, replaceFileName(fileNamePart, paramReplacements, LongPath.MaxFilenameLength - fileExtension.Length - 5)) + fileExtension,
replacements,
returnFirstExisting
);
} }
private static string replaceFileName(string filename, Dictionary<string,string> paramReplacements, int maxFilenameLength) private static string replaceFileName(string filename, Dictionary<string,string> paramReplacements, int maxFilenameLength)
{ {
//Filename limits on NTFS and FAT filesystems are based on characters,
//but on ext* filesystems they're based on bytes. The ext* filesystems
//don't care about encoding, so how unicode characters are encoded is
///a choice made by the linux kernel. As best as I can tell, pretty
//much everyone uses UTF-8.
int getFilesystemStringLength(StringBuilder str)
=> LongPath.PlatformID is PlatformID.Win32NT ?
str.Length
: Encoding.UTF8.GetByteCount(str.ToString());
List<StringBuilder> filenameParts = new(); List<StringBuilder> filenameParts = new();
//Build the filename in parts, replacing replacement parameters with //Build the filename in parts, replacing replacement parameters with
//their values, and storing the parts in a list. //their values, and storing the parts in a list.
@ -88,7 +106,7 @@ namespace FileManager
//Remove 1 character from the end of the longest filename part until //Remove 1 character from the end of the longest filename part until
//the total filename is less than max filename length //the total filename is less than max filename length
while (filenameParts.Sum(p => p.Length) > maxFilenameLength) while (filenameParts.Sum(p => getFilesystemStringLength(p)) > maxFilenameLength)
{ {
int maxLength = filenameParts.Max(p => p.Length); int maxLength = filenameParts.Max(p => p.Length);
var maxEntry = filenameParts.First(p => p.Length == maxLength); var maxEntry = filenameParts.First(p => p.Length == maxLength);

View File

@ -20,7 +20,7 @@ namespace FileManager
public string Path { get; init; } public string Path { get; init; }
public override string ToString() => Path; public override string ToString() => Path;
private static readonly PlatformID PlatformID = Environment.OSVersion.Platform; internal static readonly PlatformID PlatformID = Environment.OSVersion.Platform;
public static implicit operator LongPath(string path) public static implicit operator LongPath(string path)