so, I'm trying to create a following directory:
d:\temp\ak\ty\nul
Path is constructed in the loop, starting from: d:\temp and so on, creating non-existent directories along the way, so it first creates:
d:\temp\ak
then:
d:\temp\ak\ty
and.... then it comes to the last bit nul it throws this exception:
So, what's going on - where it took \.\nul from?
The code:
string z_base_path = #"d:\temp\ak\ty";
string z_extra_path = "nul";
string z_full_path = System.IO.Path.Combine(z_base_path, z_extra_path);
System.IO.Directory.CreateDirectory(z_full_path);
In Windows, nul is a reserved file name. No file or directory may be named that. Other reserved names include:
con
prn
aux
com{0-9}
lpt{0-9}
'nul' is a device file meaning that no file/folder can have that name.
instead of
string z_extra_path = "nul";
try
string z_extra_path = "null";
or
string z_extra_path = "";
other ones are
con
aux
com1-9
lpt1-9
prn
Never knew this one until I came against it - it's worth nothing the Windows Directory reserved names and all the rest.
Taken from about article:
https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file
Folder Naming Conventions
The following fundamental rules enable applications to create and process valid names for files and directories, regardless of the file system:
Use a period to separate the base file name from the extension in the name of a directory or file.
Use a backslash () to separate the components of a path. The backslash divides the file name from the path to it, and one directory name from another directory name in a path. You cannot use a backslash in the name for the actual file or directory because it is a reserved character that separates the names into components.
Use a backslash as required as part of volume names, for example, the "C:" in "C:\path\file" or the "\server\share" in "\server\share\path\file" for Universal Naming Convention (UNC) names. For more information about UNC names, see the Maximum Path Length Limitation section.
Do not assume case sensitivity. For example, consider the names OSCAR, Oscar, and oscar to be the same, even though some file systems (such as a POSIX-compliant file system) may consider them as different. Note that NTFS supports POSIX semantics for case sensitivity but this is not the default behavior. For more information, see CreateFile.
Volume designators (drive letters) are similarly case-insensitive. For example, "D:" and "d:" refer to the same volume.
Use any character in the current code page for a name, including Unicode characters and characters in the extended character set (128–255), except for the following:
The following reserved characters:
< (less than)
> (greater than)
: (colon)
" (double quote)
/ (forward slash)
\ (backslash)
| (vertical bar or pipe)
? (question mark)
* (asterisk)
Integer value zero, sometimes referred to as the ASCII NUL character.
Characters whose integer representations are in the range from 1 through 31, except for alternate data streams where these characters are allowed. For more information about file streams, see File Streams.
Any other character that the target file system does not allow.
Use a period as a directory component in a path to represent the current directory, for example ".\temp.txt". For more information, see Paths.
Use two consecutive periods (..) as a directory component in a path to represent the parent of the current directory, for example "..\temp.txt". For more information, see Paths.
Do not use the following reserved names for the name of a file:
CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. Also avoid these names followed immediately by an extension; for example, NUL.txt is not recommended. For more information, see Namespaces.
Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not. However, it is acceptable to specify a period as the first character of a name. For example, ".temp".
Related
I'm working on a piece of code which creates some files and copies them to a SharePoint group (i.e., a synchronised folder, like OneDrive or Dropbox).
An important detail is that the created file has a very long file path (currently 373 characters).
Once the file has been copied to the SharePoint group - and I can see that it synchronises perfectly well (so the path isn't too long for SharePoint) - I then find...
File.Exists(myLongPath) = false
I've tried calling...
Directory.GetFiles(myLongDirectory, "*.*", SearchOption.AllDirectories)
... and the file with the long path is listed, but if I copy-paste that result back into...
File.Exists(copyPastedPath)
... again the the result is false.
So Directory.GetFiles can see the file but File.Exists can't.
The documentation for FileInfo.Exists says (my emphasis)...
The Exists property returns false if any error occurs while trying to
determine if the specified file exists. This can occur in situations
that raise exceptions such as passing a file name with invalid
characters or too many characters, a failing or missing disk, or if
the caller does not have permission to read the file.
The first case - "invalid characters" - can't be the cause of my problem because I'm testing with a-z, A-Z and 0-9. So my suspicion falls on that second case - "too many characters".
Could it really be the case that the SharePoint group allows for longer path lengths than FileInfo.Exists?
I need to be able to extract the full file path out of this string (without whatever is after the file extension):
$/FilePath/FilePath/KeepsGoing/Folder/Script.sql (CS: 123456)
A simple solution such as the following could would work for this case, however it is only limited to a file extension with 3 characters:
(\$.*\..{3})
However, I find problems with this when the file contains multiple dots:
$/FilePath/FilePath/File.Setup.Task.exe.config (CS: 123456)
I need to be able to capture the full file path (from $ to the end of whatever the file extension is, which can be any number of things). I need to be able to get this no matter how many dots are in the name of the file. In some cases there are spaces in the name of the file too, so I need to be able to incorporate that.
Edit: The ending (CS....) in this case is not standard. All kinds of stuff can follow the path so I cannot predict what will come after the path, but the path will always be first. Sometimes spaces do exist in the file name.
Any suggestions?
Try this:
(\$.*\.[\w.-]+)
But! it will not properly match files with space or special chars in the file extension. If you need to match files that might have special chars in the file extension you'll need to elaborate on the input (is it quoted? is it escaped?).
So, I feel lame for asking this, but I'm kinda stumped. I'm trying to get a list of file in a directory that end in tif ... only tif ... not tiff. So, I did this in C# ...
Directory.GetFiles(path, "*.tif", SearchOption.TopDirectoryOnly);
I would expect it to only return tif files, but that is not the case. I get tiff as well. I would think that if I supplied the mask .tif? that would get me both, but not the mask .tif. I tried it at a command prompt as well and I am getting both as well in DOS. Am I missing something here? This just seems wrong to me. I guess I could sanitize the results afterwards, but if I don't have to that would be best.
From MSDN:
When using the asterisk wildcard character in a searchPattern (for
example, "*.txt"), the matching behavior varies depending on the
length of the specified file extension. A searchPattern with a file
extension of exactly three characters returns files with an extension
of three or more characters, where the first three characters match
the file extension specified in the searchPattern. A searchPattern
with a file extension of one, two, or more than three characters
returns only files with extensions of exactly that length that match
the file extension specified in the searchPattern. When using the
question mark wildcard character, this method returns only files that
match the specified file extension. For example, given two files in a
directory, "file1.txt" and "file1.txtother", a search pattern of
"file?.txt" returns only the first file, while a search pattern of
"file*.txt" returns both files.
That's just how Directory.GetFiles works. From the manual:
When using the asterisk wildcard character in a searchPattern, such as
"*.txt", the matching behavior when the extension is exactly three
characters long is different than when the extension is more or less
than three characters long. A searchPattern with a file extension of
exactly three characters returns files having an extension of three or
more characters, where the first three characters match the file
extension specified in the searchPattern.
Directory.GetFiles internally uses FindFirstFile function from Win32 API.
From the documentation of FindFirstFile:
• The search includes the long and short file names.
A file that has long file name of asd.tiff will have a short file name like asd~1.tif and this is why it shows up in the results.
More than three character extensions are matched except when the path is on a network share (or mapped drive). For some reason the pattern only matches the long file name on remote drives.
I am currently looking for a regex that can help validate a file path e.g.:
C:\test\test2\test.exe
I decided to post this answer which does use a regular expression.
^(?:[a-zA-Z]\:|\\\\[\w\.]+\\[\w.$]+)\\(?:[\w]+\\)*\w([\w.])+$
Works for these:
\\test\test$\TEST.xls
\\server\share\folder\myfile.txt
\\server\share\myfile.txt
\\123.123.123.123\share\folder\myfile.txt
c:\folder\myfile.txt
c:\folder\myfileWithoutExtension
Edit: Added example usage:
if (Regex.IsMatch (text, #"^(?:[a-zA-Z]\:|\\\\[\w\.]+\\[\w.$]+)\\(?:[\w]+\\)*\w([\w.])+$"))
{
// Valid
}
*Edit: * This is an approximation of the paths you could see. If possible, it is probably better to use the Path class or FileInfo class to see if a file or folder exists.
I would recommend using the Path class instead of a Regex if your goal is to work with filenames.
For example, you can call Path.GetFullPath to "verify" a path, as it will raise an ArgumentException if the path contains invalid characters, as well as other exceptiosn if the path is too long, etc. This will handle all of the rules, which will be difficult to get correct with a Regex.
This is regular expression for Windows paths:
(^([a-z]|[A-Z]):(?=\\(?![\0-\37<>:"/\\|?*])|\/(?![\0-\37<>:"/\\|?*])|$)|^\\(?=[\\\/][^\0-\37<>:"/\\|?*]+)|^(?=(\\|\/)$)|^\.(?=(\\|\/)$)|^\.\.(?=(\\|\/)$)|^(?=(\\|\/)[^\0-\37<>:"/\\|?*]+)|^\.(?=(\\|\/)[^\0-\37<>:"/\\|?*]+)|^\.\.(?=(\\|\/)[^\0-\37<>:"/\\|?*]+))((\\|\/)[^\0-\37<>:"/\\|?*]+|(\\|\/)$)*()$
And this is for UNIX/Linux paths
^\/$|(^(?=\/)|^\.|^\.\.)(\/(?=[^/\0])[^/\0]+)*\/?$
Here are my tests:
Win Regex
Unix Regex
These works with Javascript
EDIT
I've added relative paths, (../, ./, ../something)
EDIT 2
I've added paths starting with tilde for unix, (~/, ~, ~/something)
The proposed one is not really good, this one I build for XSD, it's Windows specific:
^(?:[a-zA-Z]\:(\\|\/)|file\:\/\/|\\\\|\.(\/|\\))([^\\\/\:\*\?\<\>\"\|]+(\\|\/){0,1})+$
Try this one for Windows and Linux support: ((?:[a-zA-Z]\:){0,1}(?:[\\/][\w.]+){1,})
I use this regex for capturing valid file/folder paths in windows (including UNCs and %variables%), with the exclusion of root paths like "C:\" or "\\serverName"
^(([a-zA-Z]:|\\\\\w[ \w\.]*)(\\\w[ \w\.]*|\\%[ \w\.]+%+)+|%[ \w\.]+%(\\\w[ \w\.]*|\\%[ \w\.]+%+)*)
this regex does not match leading spaces in path elements, so
"C:\program files" is matched
"C:\ pathWithLeadingSpace" is not matched
variables are allowed at any level
"%program files%" is matched
"C:\my path with inner spaces\%my var with inner spaces%" is matched
regex CmdPrompt("^([A-Z]:[^\<\>\:\"\|\?\*]+)");
Basically we look for everything that's not in the list of forbidden Windows Path Characters:
< (less than)
> (greater than)
: (colon)
" (double quote)
| (vertical bar or pipe)
? (question mark)
* (asterisk)
I know this is really old... but expanding on #agent-j's response I've added named groups, and support for period characters.
^(?<ParentPath>(?:[a-zA-Z]\:|\\\\[\w\s\.]+\\[\w\s\.$]+)\\(?:[\w\s\.]+\\)*)(?<BaseName>[\w\s\.]*?)$
I've saved this at Regexr
I found most of the answers here to be a little hit or miss.
Found a good solution here though:
https://social.msdn.microsoft.com/forums/vstudio/en-US/31d2bc84-c948-4914-8a9d-97b9e788b341/validate-a-network-folder-path
Note* - this is only for network shares - not local files
Answer:
string pattern = #"^\\{2}[\w-]+(\\{1}(([\w-][\w-\s]*[\w-]+[$$]?)|([\w-][$$]?$)))+";
string[] names = { #"\\my-network\somelocation", #"\\my-network\\somelocation",
#"\\\my-network\somelocation", #"my-network\somelocation",
#"\\my-network\\somelocation",#"\\my-network\somelocation\aa\dd",
#"\\my-network\somelocation\",#"\\my-network\\somelocation"};
foreach (string name in names)
{
if (Regex.IsMatch(name, pattern))
{
Console.WriteLine(name);
//Directory.Exists function to check if file exists
}
}
Alexander's Answer + Relative Paths
Alexander has the most correct answer thus far since it supports spaces in file names (i.e. C:\Program Files (x86)\ will match)... This aims to include relative paths as well.
For example, you can do cd / or cd \ and it does the same thing.
Further more, if you're currently in C:\some\path\to\some\place and you type either of those commands, you end up at C:\
Even more, you should consider paths, that start with '/' as a root path (to the current drive).
(?:[a-zA-Z]:(\|/)|file://|\\|.(/|\)|/)([^,\/:*\?\<>\"\|]+(\|/){0,1})
A Modified version of Alexander's answer, however, we include paths that are relative with no leading / or drive letter, as well as / with no leading drive letter (relative to the current drive as root).
I'm trying to upload a text file (converted to ebcdic) into a library in MVS using C#. For uploading a file, I used the following string: filename = #"ftp://xx.xx.xx.xx//'myFile'"; It is not possible without the apostrophes.
Now, I used #"ftp://xx.xx.xx.xx//'libary_name(myFile)'" for upload into a library but I get incorrect syntax or parameters error. Library name: user_id.xyz.temp_lib and myFile: user_id.xyz.someFile. How do I go about fixing this?
Also, is there a way to control the block size of the text file in c#? MVS currently states the uploaded file as VB but I want it as FB (length specified of course).
Thanks
Two thoughts...
Your first example suggests a basic misunderstanding of MVS file names.
Unlike Unix, DOS or MS Windows there is no such thing as a folder or "path". The entire MVS file is defined in the system catalog by its unique dataset name which can not exceed 44 characters. The file can vary in organizational structure which may or may not have an internal directory or index. It can be a simple flat file, or a PDS, or VSAM, or GDG, or database etc. You have to understand what type of file you are working with to use it correctly.
In this situation, you called it a "library" and you further indicated this library has a member name which strongly hints that the file is organized as a PDS dataset. As a PDS, there is an internal directory and you can have multiple members, but no single member name may exceed 8 bytes. The member name counts toward the 44 byte name space limitation of the file name. As Erf indicated, the PDS member name is limited to letters, numbers and a few national characters. The data within the member is accessed sequentially.
In your first example you indicated the member name is: user_id.xyz.someFile
That name is obviously invalid as it exceeds the 8 byte limit. If you had shortend the name your example may have worked. Indeed, it appears in your corrected example that you fixed the illegal member name issue by creating a PDS member called "someFile" and that is pefectly valid.
2nd thought...
You said "If you use the full MVS data set path on this command, you will get an error."
That statement sounds incorrect and indicates you may not have allowed for the fact that the FTP session is appending the user id to your file name automatically. While allowing FTP to default your file name works fine, in most cases you should explicitly qualify the entire MVS file name.
Without the apostrophes, FTP should append your user id to the MVS file name by default. The following names are equivalent...
#"ftp://xx.xx.xx.xx//libary_name(aMember)"
#"ftp://xx.xx.xx.xx//'user_id.libary_name(aMember)'"
With the apostrophes, FTP expects you to explicitly name the fully-qualified MVS file name. It will not append the user id for you.
This example shows the difference:
#"ftp://xx.xx.xx.xx//libary_name(aMember)" <- user_id.libary_name(aMember)
#"ftp://xx.xx.xx.xx//'xyz.libary_name(aMember)'" <- xyz.libary_name(aMember)
You mentioned that FTP will not work without apostrophes. That surprises me. Have you tried using the C# escape double-quote (\") character instead? I think that would work as well.
Fixed it!
Instead of #"ftp://xx.xx.xx.xx//'libary_name(myFile)'" where Library name: user_id.xyz.temp_lib and myFile: user_id.xyz.someFile, you have to use
#"ftp://xx.xx.xx.xx//'libary_name(someFile)'" If you use the full MVS data set path on this command, you will get an error.
For the MVS ftp server, you don't use the MVS style dataset name. Each node in the dataset name is treated as a directory. For example, if you started at "/", you could:
chdir user_id
chdir xyz
chdir temp_lib
ls
would get you a listing of all the members in the library user_id.xyz.temp_lib.
To upload, try #"ftp:/xx.xx.xx.xx/user_id/xyz/temp_lib/myFile".
To get the file in FB, you can use the DCbdsn command:
214-DCbdsn=data_set Specifies that FTP should allocate any new data sets
214- with the same attributes as this data set. Data_set is
214- either a fully qualified data set name in quotes
214- or appended to the present directory name prefix.
214- Blocksize, lrecl, recfm and retpd parameters will override
214- the model data set characteristics if they are specified.
You can also use the Blocksize, lrecl or recfm options independantly.