How can I use (to avoid PathTooLongException):
System.IO.FileInfo
with paths bigger than 260 chars?
Are there similar classes/methods that return the same result of FileInfo class?
From what I know it is not easily possible. While it is possible to use workaround for streams as phoenix mentioned, it is not possible for file names handling. Internally every class that works with file names perform checks for long file names.
You can instantiate FileInfo and fill private memebers using reflection (however this is not recommended) and get FileInfo pointing to file with long path. But when you try to use this object you will still receive PathTooLongException exceptions, because for example, Path class (used heavily by FileInfo) checks for long path on every method call.
So, there is only one right way to get problem free long path support - implement your own set of classes that will mimic FileInfo behavior. It is not very complex (only security maybe), but time-consuming.
Update: Here even two ready solutions for this problem: AlpfaFS and Zeta Long Paths
Here at work we deal with long paths quite frequently, and we therefore had to basically roll our own System.IO to do it. Well not really, but we rewrote File, Directory, FileInfo, DirectoryInfo and Path just to name a few. The basic premise is that it's all possible from a Win32 API perspective, so all you really need to do at the end of the day is invoke the Unicode versions of the Win32 API functions, and then you're good. It's alot of work, and can be a pain in the ass at times, but there's really no better way to do it.
There's a great library on Microsoft TechNet for overcoming the long filenames problem, it's called
Delimon.Win32.IO Library (V4.0) and it has its own versions of key methods from System.IO
For example, you would replace:
System.IO.Directory.GetFiles
with
Delimon.Win32.IO.Directory.GetFiles
which will let you handle long files and folders.
From the website:
Delimon.Win32.IO replaces basic file functions of System.IO and
supports File & Folder names up to up to 32,767 Characters.
This Library is written on .NET Framework 4.0 and can be used either
on x86 & x64 systems. The File & Folder limitations of the standard
System.IO namespace can work with files that have 260 characters in a
filename and 240 characters in a folder name (MAX_PATH is usually
configured as 260 characters). Typically you run into the
System.IO.PathTooLongException Error with the Standard .NET Library.
I only needed to use the FullName property but was also receiving the PathTooLongException.
Using reflection to extract the FullPath value was enough to solve my problem:
private static string GetFullPath(FileInfo src)
{
return (string)src.GetType()
.GetField("FullPath", BindingFlags.Instance|BindingFlags.NonPublic)
.GetValue(src);
}
Related
I am trying to figure out whether a global string resource file for the entire application or a local resource file for each small sub area would be a better choice.
It seems like a translator would appreciate the one file approach vs hundreds of them. It is also easier to write helper functions since there is only going to be one static resource class.
The downside is that the resource name might be really long to properly identify the place where it is suppose to be in and it might be hard to locate related strings when the file grows big.
Where as a local resource file would produce lots of duplicated strings or make it confusing if we need to use multiple instances of static resource classes because the strings are spread between multiple of them.
So what would be a better way to go?
Maybe you could break your resources into 3 files (depending on your application design):
ResourcesCore
For translated enum values and common expressions
ResourcesEntity
For strings related to translation of some entity properties (e.g. Person.Name)
ResourcesWeb (or ResourceUI)
For other UI related stuff (like strings on UI, labels, descriptions, etc.)
You could then use ResXManager extension for VS to manage you resource strings (way easier than native .NET ResX manager, at least for me).
Extreme noob learning question ahead:
I have a module that I'd like to use in my C# (universal) application. The C# app will download and unzip a file containing 12 CSVs that will always follow the same format. So what I've done is download the CSVs ahead of time, and added them to my solution so that the file referenced in CsvProvider<"thefile.csv"> will be there at compile time.
namespace ExperimentalFSLibrary
module CsvHelper =
open FSharp.Data
let GetCsvA path =
CsvProvider<"thefileA.csv">.Load(path)
Then call this from my c# application like so:
var ReceivedCsvA = ExperimentalFSLibrary.CsvHelper.GetCsvA
I haven't had any success getting the data from the F# library
There's also the issue of how to deal with twelve different files, since I have to specify the template file for the CsvProvider, I imagine I'd have to write 12 different functions?
I've searched around SO and have found things that have gotten me this far but I've hit a wall. Any help including a sanity check would be very appreciated.
The CsvProvider in FSharp.Data is an erasing type provider. This means there is no type to consume and use from within C#.
Many F# type providers, such as this, will only be beneficial when used from within F#.
In this case, you'd most likely be better off parsing the CSV data and returning the results you need via some API consumable from your C# code.
There's also the issue of how to deal with twelve different files, since I have to specify the template file for the CsvProvider, I imagine I'd have to write 12 different functions?
In general, you'd need a separate function per file structure, not per file. If the 12 files all use the same columns/headers/etc, then a single type provider type will work across each of them. The static filename provided is used only to determine the column structure of the generated types.
I store a whole bunch of files as embedded resources within an assembly. Calling Assembly.GetManifestResourceNames returns things similar to the following:
Folder1.Resource1.cshtml
Folder1.Folder2.common.js
etc.
I have a class that builds a virtual directory/file system based on these names. However, I am having an issue with resources such as:
Folder1.Folder2.jQuery-ui-1.10.3.custom.min.js
As there is no way (unless you handle it as a special case) to know that jquery-ui-1 and 10 and 3, etc are not folder names, with a final resource of min.js. Currently I get around this by ensuring that all my embedded resources do not contain multiple periods. That said, is there a way to change the path separator to a different character to avoid this problem entirely?
Are you able to get the ResourceManager? If so, you can use BaseName
You could use the Assembly.GetTypes() to use the type to get to the ResourceManager, or you could even potentially cross reference directly against the FullName of the Types.
I'm currently working with some code involving saving a file to a user-defined file. If the user passes in a filename with no extension, the code autodetects the extension based on the file type (stored internally).
However, I'm having a hard time determining whether the filename passed to the code has an extension or not. I'm using Path.HasExtension(filename) and Path.GetExtension(filename) but it seems to be exhibiting strange behavior:
File.EXT => .EXT is the extension. This is fine.
This Is A File.EXT => .EXT is the extension. This is also fine.
This Is A File. Not An Extension => . Not An Extension is the extension. However, I would think of this as a file without an extension. Windows thinks so too when I create a file with this name (creating a file with an unrecognized extension causes windows to call it a EXTENSIONNAME File, whereas files without an extension such as this one are just called File).
This Is A File.Not An Extension => .Not An Extension is the extension. Same problem as above.
Also note that this same behavior is evident in Path.GetFileNameWithoutExtension(filename) (e.g. it reports the filename without extension on the last two examples to be just This Is A File).
So what I'm taking from this is that .NET and Windows differ on what they think of as an extension.
The Question:
I'm wondering if it's OK for me to implement code such as this:
if(!Path.HasExtension(filename) || Path.GetExtension(filename).Contains(" ")) {...}
since that would pull my code's definition of a proper extension more in line with how Windows treats things. Or is there something I'm missing here which explicitly says I must allow spaces in my extensions?
I've searched and found this slightly similar question, but the documents linked therein only specify that it's not recommended to end the extension with a space/period -- they say nothing about spaces within the extension.
The extension on a filename in Windows is purely a convention. The GetExtension and HasExtension methods only look for a dot in the filename and act accordingly. You are free to put spaces anywhere you like within the filename (including the extension).
When you say "Windows thinks so too", it's really just some code in Explorer that tries to parse out extensions, and it simply uses a slightly different algorithm than .NET.
How the filesystem handles names and how the Windows shell (i.e. Explorer) handles file names are two completely different beasts.
The filesystem doesn't care about spaces, dots or anything else -- to it, the filename is just one opaque string (with some restrictions on allowed characters). The name/extension separation is just a made-up convention. The shell, on the other hand, is free to make up its own interpretation of what an extension is because its purpose is not to store and retrieve file information but rather to provide the user with a better experience. So don't go looking there for answers.
I would suggest going with what the System.IO methods return (because following the convention is good), but you can do whatever you like in your code if there's a good reason for it.
There is no official definition of what an extension is. The common convention is that everything after the final . is the extension.
However if you would grab a HUGE list of all common-used extensions I think you'll only find a handful of examples where spaces in an extension are used.
I would say, disallow spaces in extensions. 999/1000 times the user didn't mean it as an extension.
To quote Wikipedia on filenames:
. (DOT): allowed but the last occurrence will be interpreted to be the extension separator in VMS, MS-DOS and Windows. In other OSes, usually considered as part of the filename, and more than one full stop may be allowed.
Is it possible to either use the System.IO.Path class, or some similar object to format a unix style path, providing similar functionality to the PATH class? For example, I can do:
Console.WriteLine(Path.Combine("c:\\", "windows"));
Which shows:
"C:\\windows"
But is I try a similar thing with forward slashes (/) it just reverses them for me.
Console.WriteLine(Path.Combine("/server", "mydir"));
Which shows:
"/server\\mydir"
You've got bigger problems, Unix accepts characters in a file name than Windows does not allow. This code will bomb with ArgumentException, "Illegal characters in path":
string path = Path.Combine("/server", "accts|payable");
You can't reliably use Path.Combine() for Unix paths.
Path.Combine uses the values of Path.DirectorySeperatorChar and Path.VolumeSeparatorChar, and these are determined by the class libraries in the runtime - so if you write your code using only Path.Combine calls, Environment.SpecialFolder values, and so forth, it will run fine everywhere, since Mono (and presumably any .NET runtime) implements the native way of getting and building those paths for any platform it runs on. (Your second example, for instance, returns /server/mydir for me, but the first example gives c:\/windows )
If you want a UNIX-specific path hard-coded in all cases, Path.Combine isn't buying you anything: Console.WriteLine ("/server/mydir"); does what you want in the OP.
As Hans said though, different filesystems have different rules for allowed characters, path lengths, and etc., so the best practice, like with any cross-platform programming, is to restrict yourself to using the intersection of allowed features between the filesystems you're targeting. Watch case-sensitivity issues too.
In this case i would use the class System.Uri or System.UriBuilder.
Side note: If you run your .NET code on a Linux-System with the Mono-Runtime, the Path class should return your expected behavior. The information that the Path class uses are provided by the underlying system.