我正在为我们的应用程序开发图形安装程序。由于所有可用的安装程序生成器都不符合要求和限制,因此我从头开始构建它。
安装程序应该在多个操作系统上运行,因此路径处理需要与操作系统无关。我为此目的编写了以下小实用程序:
public class Path {
private Path() {
}
public static String join(String... pathElements) {
return ListEnhancer.wrap(Arrays.asList(pathElements)).
mkString(File.separator);
}
public static String concatOsSpecific(String path, String element) {
return path + File.separator + element;
}
public static String concatOsAgnostic(String path, String element) {
return path + "/" + element;
}
public static String makeOsAgnostic(String path) {
return path.replace(File.separator, "/");
}
public static String makeOsSpecific(String path) {
return new File(path).getAbsolutePath();
}
public static String fileName(String path) {
return new File(path).getName();
}
}
现在我的代码在很多地方都被Path.*Agnostic
和Path.*Specific
调用了。很明显,这很容易出错,根本不透明。
我应采取什么方法来使路径处理透明且不易出错?是否存在已解决此问题的任何实用程序/库?任何帮助将不胜感激。
修改
为了举例说明我的意思,这里是我刚才写的一些代码。 (Offtopic:原谅长期的方法。代码处于初始阶段,很快就会进行一些重构。)
某些上下文:ApplicationContext
是存储安装数据的对象。这包括几个路径,例如installationRootDirectory
,installationDirectory
等。这些路径的默认值在创建安装程序时指定,因此始终以与操作系统无关的格式存储。
@Override
protected void initializeComponents() {
super.initializeComponents();
choosePathLabel = new JLabel("Please select the installation path:");
final ApplicationContext c = installer.getAppContext();
pathTextField = new JTextField(
Path.makeOsSpecific(c.getInstallationDirectory()));
browseButton = new JButton("Browse",
new ImageIcon("resources/images/browse.png"));
browseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setAcceptAllFileFilterUsed(false);
int choice = fileChooser.showOpenDialog(installer);
String selectedInstallationRootDir = fileChooser.getSelectedFile().
getPath();
if (choice == JFileChooser.APPROVE_OPTION) {
c.setInstallationRootDirectory(
Path.makeOsAgnostic(selectedInstallationRootDir));
pathTextField.setText(Path.makeOsSpecific(c.getInstallationDirectory()));
}
}
});
}
答案 0 :(得分:4)
或者你可以介绍2个新课程:
class OsSpecificPath implements FilePathInterface
{
String path;
OsAgnosticPath toAgnosticPath();
OsSpecificPath concat( OsSpecificPath otherPath );
// from IFilePath
getFile();
... etc
}
和
class OsAgnosticPath implements FilePathInterface
{
String path;
OsSpecificPath toOsSpecificPath();
OsAgnosticPath concat( OsAgnosticPath otherPath );
// from IFilePath
getFile();
... etc
}
每个人都需要包装路径。
然后每个方法都可以有方法转换为其他类型的路径,但不是“字符串式”解决方案,其中一切都是字符串,可以被滥用,你有2个强类型的类,不能被错误地传递。
任何不关心路径类型的东西都会使用FilePathInterface
,任何需要在特定路径上运行的东西都会特别使用这些类型。如果真的有必要,FilePathInterface
可以假设在界面中同时包含toAgnosticPath
和toOsSpecificPath
......
答案 1 :(得分:1)
不确定这是否适合您,但通常当我需要在独立于操作系统的Java程序中执行与路径相关的操作时,我总是使用字符串来传递路径而不是文件,我总是这样做以下两件事:
每当我构建一个String路径时,我总是使用/
作为文件分隔符
每当我使用String路径创建文件或将其保存为某处文本时,我总是在使用路径之前进行以下调用:
String fSep = System.getProperty("file.separator);
String path = ... //might be built from scratch, might be passed in from somewhere
path = path.replace("/",fSep).replace("\\",fSep);
无论路径是在本地计算机上构建还是从具有不同操作系统的网络上的其他计算机传入,这似乎都能正常工作,前提是我打算在本地计算机上使用该路径。如果您计划通过网络传递不同操作系统之间的路径,请注意您自己的代码是否一致。
修改
哇......不知何故,我的答案被破坏了,而且代码格式化并没有像最初预期的那样起作用......
答案 2 :(得分:0)
我会创建自己的MyFile对象来扩展或包装java.util.File。然后确保所有代码都使用此对象而不是java.io.File。在这里,您将执行操作系统检查并调用方法来清理文件名。你的其余代码将是“干净的”。
答案 3 :(得分:0)
您永远不需要将返回转换为os-agnostic。以下是特定于操作系统的转换:
public class Path {
private Path() {
}
public static String concat(String path, String element) {
return new File(path, element).getPath();
}
public static String makeOsSpecific(String path) {
return new File(path).getAbsolutePath();
}
public static String fileName(String path) {
return new File(path).getName();
}
}
您的样本:
@Override
protected void initializeComponents() {
super.initializeComponents();
choosePathLabel = new JLabel("Please select the installation path:");
final ApplicationContext c = installer.getAppContext();
pathTextField = new JTextField(
Path.makeOsSpecific(c.getInstallationDirectory()));
browseButton = new JButton("Browse",
new ImageIcon("resources/images/browse.png"));
browseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChooser.setAcceptAllFileFilterUsed(false);
int choice = fileChooser.showOpenDialog(installer);
String selectedInstallationRootDir = fileChooser.getSelectedFile().
getPath();
if (choice == JFileChooser.APPROVE_OPTION) {
c.setInstallationRootDirectory(selectedInstallationRootDir);
pathTextField.setText(Path.makeOsSpecific(c.getInstallationDirectory()));
}
}
});
}