I want to open a given file "directory/subdirectory/file.txt" in golang. What is the recommended way to express such a path in an OS agnostic way (ie backslashes in Windows, forward slashes in Mac and Linux)? Something like Python's os.path module?
For creating and manipulating OS-specific paths directly use os.PathSeparator and the path/filepath package.
An alternative method is to always use '/' and the path package throughout your program. The path package uses '/' as path separator irrespective of the OS. Before opening or creating a file, convert the /-separated path into an OS-specific path string by calling filepath.FromSlash(path string). Paths returned by the OS can be converted to /-separated paths by calling filepath.ToSlash(path string).
Use path/filepath instead of path. path is intended for forward slash-separated paths only (such as those used in URLs), while path/filepath manipulates paths across different operating systems.
Example:
package main
import (
"fmt"
"path/filepath"
)
func main() {
path := filepath.Join("home", "hello", "world.txt")
fmt.Println(path)
}
Go Playground: https://go.dev/play/p/2Fpb_vJzvSb
Based on the answer of #EvanShaw and this blog the following code was created:
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
p := filepath.FromSlash("path/to/file")
fmt.Println("Path: " + p)
}
returns:
Path: path\to\file
on Windows.
Go treats forward slashes (/) as the universal separator across all platforms [1]. "directory/subdirectory/file.txt" will be opened correctly regardless of the runtime operating system.
Related
I have a service which refers to some external filesystem resources like html, css, etc, ... which fails to load in Windows because of passing incorrect path to them.
Is there any way I could retrieve the file separator of the operating system in Qorus (I mean slash or backslash depending on the system) so that I could build the proper resource path?
I know there is a function to get the path of a file normalize_dir()
and based on it can be decided what separator to use
string file_separator = normalize_dir("").find("/") > 0 ? '/' : '\';
setDefaultResource("html" + file_separator + "index.qhtml");
but I was wondering if there is already something in place that return this char (as I was not able to find something similar in the docs) or a similar function that I could reuse.
You can use Qore string constant DirSep described in documentation, which always contains the platform-specific directory separator string, i.e. / for Linux and other Unix-like OSes, and \ for Windows.
According to Supported Win32 APIs for Windows Phone 8, WP8 does support many file manipulation APIs in fileapi.h like CreateFile2, ReadFile, WriteFile, ...
But when I include <stdio.h> I can use fopen, fread, fwrite, ...
Using both those APIs, I can create and read/write to a text file.
CreateFile2("hello.txt", ...);
fopen("hello.txt", ...);
... means other parameters, which aren't important to this question.
The other thing is that I don't know where that text file resides. Installed location isn't the case, because it is read-only location. The other case is Local folder, but I don't specify any Local folder path.
So what are the differences between those APIs (in fileapi.h and stdio.h) and which location does they act on ?
P/S: I'm doing in the WP Runtime Component
The main difference is the API set these functions use.
<stdio.h> contains the file APIs of the standard C library, <fileapi.h> is the Win32 APIs. There are also C++ APIs (<iostream>) which you could use.
I've found that whatever API you use, you should explicitly set the file location to the Local folder.
Platform::String^ localfolder = Windows::Storage::ApplicationData::Current->LocalFolder->Path;
Platform::String^ myFileName = Platform::String::Concat(localfolder, "\\myfile.txt");
One thing to watch is that Platform::String^ uses wchar_t, not char internally so you need to be a bit careful in specifying the file name.
So, try and find an API that takes wchar_t* for the file name and use that to avoid having to do character set conversion.
E.g.: Use _wfsopen instead of fopen.
I am curious about using dlopen in Linux to call shared libraries.
Suppose I want to use a shared library in C whose name is fileName.so. I am working in a 64bit Ubuntu Linux and I include dlfcn.h and use dlopen function to access the shared library.
When I use dlopen(fileName.so, RTLD_LAZY), a NULL handle is returned and shared library is not opened. However, when I use dlopen("./fileName.so", RTLD_LAZY) the dlopen does its job and opens the shared library. It seems that the main point is in using ./ before file name.
It is appreciated if help me figure out why I should use ./ in my code. Thanks
POSIX says that dlopen() has to know where to look for the file and leaves the behaviour when the file name does not include a / implementation defined. On Linux, if you don't supply a pathname (a name with a / in it somewhere), then dlopen() only looks in 'standard places', specified by environment variables such as LD_LIBRARY_PATH or via /etc/ld.so.conf (or /etc/ld.so.cache; see also ldconfig(8)) or in standard places such as /lib and /usr/lib.
When you specify the relative name ./fileName.so, it knows to look in the current directory, which is not normally a place it looks.
Note that you can run into some interesting issues on systems that support both 32-bit and 64-bit executables, with various conventions being used for the locations of the different classes of library. Other variants of Unix use vaguely related systems — mostly using dlopen() et al these days (historically, it was not always thus), and using a wide variety of environment variables (DYLD_LIBRARY_PATH, LIBPATH, SHLIB_PATH, LD_RUN_PATH, LD_LIBRARY_PATH_32, LD_LIBRARY_PATH_64, ...).
./ is a relative path to the .so file. It means that the file is in the current directory.
In *nix, by default, when given a file name without an absolute or relative path, dlopen will search for the library in a set list of default locations.
The "main point" is in using double-quotes in your second example:
dlopen("./fileName.so", RTLD_LAZY)
If you want to include your own library/filename enclose it in double-quotes. You don't even need the ./ for that, provided that the file is in the current directory, as ./ suggests.
As per the dlopen manpage's example:
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
the filename is enclosed in quotes.
Though, as specified by a previous answer, dlopen will look in the "standard" places for "includes". Another way of including a library that's inside your working directory (though, obviously, not a shared system library) is to use the preprocessor directive with the filename enclosed within double quotes:
#include <stdio.h>
#include <stdlib.h>
#include "myCustomLibrary.h"
I used DriverPackageUninstall, to uninstall my driver. For this API I need to give "Inf Path" as the input. And I need to give this path as UNICODE string. To do this, I took the following statement from MSDN as reference.
For a Unicode string, the maximum length is 32,767 characters. If you
use the Unicode version, prepend the "\?\" string to the path. For
general information about the format of file path strings, see Naming
a File in the MSDN Library.
But when I try the same in my code its not working. Can someone give me some examples on how to prepend the "\?\" before the path? Thanks..
UPDATE :
I tried with the below code as sample
#define UNICODE
#define _UNIOCDE
#define WINVER 0x501
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
int main () {
PTCHAR DriverPackageInfPath = TEXT("\\?\\c:\\Documents and Settings\\Desktop\\My.inf");
FILE * Log;
Log = _wfopen( TEXT(DriverPackageInfPath, TEXT("a"));
if ( Log == NULL ) {
MessageBox(NULL, TEXT ( "Unable to open INF file\n" ),
TEXT ( "Installation Error" ), 0 | MB_ICONSTOP );
exit ( 1 );
} else {
printf ("INF file opened successfully\n");
}
return 0;
}
UPDATE:
".\dist\Driver\My.inf" How to add "\\?\" before this kind of paths? "\\?\.\dist\Driver\My.inf" is not working.
You have error in string constant:
TEXT("\\?\\c:\\Documents ...."
should be
TEXT("\\\\?\\c:\\Documents ...."
Read carefully, escape carefully : http://msdn.microsoft.com/en-us/library/windows/hardware/ff552316%28v=vs.85%29.aspx
UPDATE:
From http://msdn.microsoft.com/en-us/library/aa365247.aspx :
Win32 File Namespaces
The Win32 namespace prefixing and conventions are summarized in this section and the following section, with descriptions of how they are used. Note that these examples are intended for use with the Windows API functions and do not all necessarily work with Windows shell applications such as Windows Explorer. For this reason there is a wider range of possible paths than is usually available from Windows shell applications, and Windows applications that take advantage of this can be developed using these namespace conventions.
For file I/O, the "\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system. For example, if the file system supports large paths and file names, you can exceed the MAX_PATH limits that are otherwise enforced by the Windows APIs. For more information about the normal maximum path limitation, see the previous section Maximum Path Length Limitation.
Because it turns off automatic expansion of the path string, the "\?\" prefix also allows the use of ".." and "." in the path names, which can be useful if you are attempting to perform operations on a file with these otherwise reserved relative path specifiers as part of the fully qualified path.
Win32 Device Namespaces
The "\.\" prefix will access the Win32 device namespace instead of the Win32 file namespace. This is how access to physical disks and volumes is accomplished directly, without going through the file system, if the API supports this type of access. You can access many devices other than disks this way (using the CreateFile and DefineDosDevice functions, for example).
For example, if you want to open the system's serial communications port 1, you can use "COM1" in the call to the CreateFile function. This works because COM1–COM9 are part of the reserved names in the NT namespace, although using the "\.\" prefix will also work with these device names. By comparison, if you have a 100 port serial expansion board installed and want to open COM56, you cannot open it using "COM56" because there is no predefined NT namespace for COM56. You will need to open it using "\.\COM56" because "\.\" goes directly to the device namespace without attempting to locate a predefined alias.
Another example of using the Win32 device namespace is using the CreateFile function with "\.\PhysicalDiskX" (where X is a valid integer value) or "\.\CdRomX". This allows you to access those devices directly, bypassing the file system. This works because these device names are created by the system as these devices are enumerated, and some drivers will also create other aliases in the system. For example, the device driver that implements the name "C:\" has its own namespace that also happens to be the file system.
APIs that go through the CreateFile function generally work with the "\.\" prefix because CreateFile is the function used to open both files and devices, depending on the parameters you use.
If you're working with Windows API functions, you should use the "\.\" prefix to access devices only and not files.
Most APIs won't support "\.\"; only those that are designed to work with the device namespace will recognize it. Always check the reference topic for each API to be sure.
So your relative path can be
\\?\.\dist\driver\My.inf
escaped form is
\\\\?\\.\\dist\\driver\\My.inf
You only need to prepend \\?\ to the path if it is longer than MAX_PATH characters.
Compiling on the shared CentOS server is not allowed. Therefore, I compile my program in my Debian computer, linking it with Debian's system libraries such as libc, etc. Then I upload my program and the Debian system libraries and my program works. The only problem is that setlocale() does not work at CentOS. CentOS has "en_US.utf8" installed and works on all programs except mine. I suspect that I have to also upload Debian's locale files ? How could I link my program to the Debian locale files ? I tried to use LOCPATH but I am unsure of how it works exactly. Which files do I have to link to and how ?
C program:
setenv("LOCPATH", "/", 1);
if (setlocale(LC_ALL, "en_US.utf8") == NULL) {
puts("not set");
}
I used a hex editor to modify the path to /usr/lib/locale/locale-archive which apparently is the only file that setlocale() uses according to strace. This method is dirty but it worked.
According to man LOCPATH, this environment variable is non-standard, so its use is not recommended. No examples are given anywhere of how to use it nor what is meant exactly by a path to "locale's object files".
I guess the only real way of modifying the path is a glibc modification and recompilation.
Quote: LOCPATH is an environment variable that tells the setlocale() function the name of the directory from which to load locale object files. If LOCPATH is not defined, the default directory /usr/lib/nls/locale is searched. LOCPATH is similar to the PATH environment variable; it contains a list of z/OS UNIX directories separated by colons.
So just specifying / and hoping that it does a recursive search will not work.
You could also produce a static binary and upload that to the host.