Nächste Nacht und schon kommen die nächsten Probleme. Zur Übergabe von Dateiinfos nutze ich gern die FileInfo-Klasse vom .NET. Und bei dem heutigen Projekt geht es darum durch Verzeichnisse der Festplatte zu stöbern und dort verschiedene Sachen zu indexieren. Hat man nun einen Pfad + Dateiname der über 260 Zeichen lang ist, kann man FileInfo nicht mehr instanzieren und bekomme eine PathTooLongException geworfen.
If your code does not have PathDiscovery permission, the error message for this exception may contain only file or directory names instead of full paths.
Full paths must not exceed 260 characters to maintain compatibility with Windows operating systems. For more information about this restriction, see the entry Long Paths in .NET in the BCL Team blog.
Diesem Problem hat sich auch das BCL Team schon gewidmet. Biete aber nur ein Workarround über die Win32-API an. 🙁
Bei meinen Versuchen stelle ich aber fest, dass wenn ich ein Verzeichniss durchlaufe, ich von DirectoryInfo.getFiles() aber FileInfo Instanzen bekomme! Dies widerspricht dann der Möglichkeit dass man FileInfo nicht mit überlangen Dateinamen benutzen kann.
D.h. man kann eben doch über diesen Umweg an ein FileInfo-Objekt gelangen. Dazu ein kurzer Workarround. Dabei wird einfach das DirectoryInfo Objekt mit dem Pfad instanziert und die Datei gesucht. Das dauert sicher ein paar ms – Aber besser als garnichts.. Man müßte jetzt benchmarken was schneller geht. Diese Lösung ständig zu benutzen oder nur im Exception-Fall.
public static FileInfo GetFileInfoForALongPath(string fullFilenameWithPath) { int pos = fullFilenameWithPath.LastIndexOf('\\'); string pfad = fullFilenameWithPath.Substring(0, pos); string filename = fullFilenameWithPath.Substring(pos + 1); var di = new DirectoryInfo(pfad); foreach (FileInfo file in di.GetFiles()) { if (file.Name == filename) return file; } return null; }
Den könnte man nun noch dahingehend erweitern dass man im Root-Verzeichnis anfängt und sich erstmal in das Verzeichniss hangelt, um dann dort die Datei suchen zu lassen – das werde ich dann nutzen wenns soweit ist 😉
Mittels LINQ kann man das ganze dann noch optimieren:
....] var di = new DirectoryInfo(pfad); return di.GetFiles().FirstOrDefault(file => file.Name == filename); }
In Foren findet man häufig die Zeichenkette \\?\ an den Pfadnamen vorran stellen zu sollen. Leider ignoriert das FileInfo-Objekt diese Anweisung. Für weitere Workarrounds kann ich den Workarround auf Codeproject.com empfehlen. Dieser bietet weitere Klassen an um auch Streams usw zu öffnen. Da aber mit der Win32API-Umgehung.
- http://blogs.msdn.com/b/michkap/archive/2006/12/13/1275292.aspx BCL Blog
- http://www.codeproject.com/Articles/22013/NET-2-0-Workaround-for-PathTooLongException Workarround in .NET – ähnlich der BCL Blog Lösng
- http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/7e8dc0a1-fe38-43e6-8431-edffc83718bf/ Diskussion im MSDN Forum
- http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx noch mehr Background zum Thema