Paths
Generating file paths can be a tedious task and error prone if you want your paths to be cross platform.
Fortunately there is a solution at hand.
The paths package includes a number of global functions that let us create and manipulate file paths.
- join
- dirname
- extension
- basename
- basenameWithoutExtension
- truepath - this is actually a DCli provided method.
- canonicalize
The path package is included as part of DCli so you don't need to add a dependency to your pubspec.yaml.
The join function is probably the most used path function. It combines components of a path into a single path.
The best way to understand it is via some examples.
var tmp = join(rootPath, 'tmp', 'abc', 'image.txt');
print(tmp);
> /tmp/abc/image.txt
'rootPath' is a DCli property that is the root directory for your OS. On Linux and Mac OS this is '/', on Windows this is 'C:' (dependent on your current working directory).
var apps = join(HOME, 'apps');
var tmp = join(apps, 'which.dart');
print(tmp);
> /home/me/which.dart
HOME is a DCli property which returns the value of the environment variable 'HOME' (in this example /home/me)
In the above example we can see that the join function combines two path fragments to form a complete path.
The dirname function returns the directory path of a file path:
var tmp = join(rootPath, 'tmp', 'abc', 'image.txt');
print(tmp);
> /tmp/abc/image.txt
print(dirname(tmp));
> /tmp/abc
The dirname function will also strip the last directory of a path is the passed path doesn't have a filename.
var tmp = join(rootPath, 'tmp', 'abc');
print(tmp);
> /tmp/abc
print(dirname(tmp));
> /tmp
The dirname function is often used to traverse up a directory tree.
var tmp = join(rootPath, 'tmp', 'abc');
while (tmp != rootPath) {
print(tmp);
tmp = dirname(tmp);
}
print(tmp);
> /tmp/abc
> /tmp
> /
The extension function returns the extension of a file.
var tmp = join(rootPath, 'tmp', 'abc', 'image.txt');
print(tmp);
> /tmp/abc/image.txt
print(extension(tmp));
> txt
The basename function returns the filename.
var tmp = join(rootPath, 'tmp', 'abc', 'image.txt');
print(tmp);
> /tmp/abc/image.txt
print(basename(tmp));
> image.txt
basenameWithoutExtension
The basenameWithoutExtension function turns the filename without the extension.
var tmp = join(rootPath, 'tmp', 'abc', 'image.txt');
print(tmp);
> /tmp/abc/image.txt
print(basenameWithoutExtension(tmp));
> image
Truepath is s DCli function rather than a 'path' function.
The truepath combines a number of 'path' functions to return an absolute path that has been normalised.
A normalised path is one which has had the '..' components resolved.
A common mistake made by many CLI applications when reporting errors is to report relative paths.
/// if you pwd is /usr/home
truepath('adirectory') == '/usr/home/adirectory';
truepath('..\adirectory') == '/usr/adirectory';
truepath('..', 'adirectory') == '/usr/adirectory';
truepath(rootPath, 'usr', 'home', 'adirectory') == '/usr/home/adirectory';
// on windows
truepath(rootPath, 'usr', 'home', 'adirectory') == 'C:\usr\home\adirectory';
For the user of your application it can often be difficult to determine what the relative path is relative to. All DCli errors that contain a path call truepath so that the path is absolute and normalised, this gives your users the best chance of correctly identifying the file or path that caused the problem.
You should also normalised any path that a user enters. Using '..' to bypass security checks is a common hacking trick.
If you need to compare to paths you need to both canonicalize your path. As Windows paths are case-insensitive the canonicalize operations returns a all lowercase version of the path which ensures to equivalent paths will return true when a string comparison is performed. The call to canonicalize will also normalize the path.
The only safe way to compare two paths it to compare two absolute paths that have been canonicalized:
canonicalize(absolute('adirectory')) == '/current/dir/adirectory';
The
absolute
call assumes that adirectory
is in the current working directory. To get the absolute path of a directory relative to some other directory use relative
.canonicalize(relative('adirectory', from: '/home/me')) == '/home/me/adirectory';
Last modified 1yr ago