2

アプリケーションのグラフィカルインストーラーを開発しています。利用可能なインストーラー ジェネレーターのいずれも要件と制約を満たしていないため、ゼロから構築しています。

インストーラーは複数のオペレーティング システムで実行されることになっているため、パスの処理は OS に依存しない必要があります。この目的のために、次の小さなユーティリティを作成しました。

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.*AgnosticPath.*Specific呼び出しています。明らかなように、これは非常にエラーが発生しやすく、まったく透過的ではありません。

パス処理を透過的にし、エラーが発生しにくいようにするには、どのようなアプローチを取る必要がありますか? この問題に既に対処しているユーティリティ/ライブラリはありますか? どんな助けでも大歓迎です。

編集:

私が言いたいことを例証するために、ここに私が少し前に書いたコードがあります。(オフトピック: 長い方法を許してください。コードは初期段階にあり、すぐにいくつかの重いリファクタリングが行われます。)

一部のコンテキスト:ApplicationContextインストール データを格納するオブジェクトです。installationRootDirectoryこれには、などのいくつかのパスが含まれますinstallationDirectory。これらのデフォルトは、インストーラーの作成時に指定されるため、常に OS に依存しない形式で保存されます。

@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()));
      }
    }
  });
}
4

4 に答える 4

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両方を含めることができます...toAgnosticPathtoOsSpecificPath

于 2012-05-31T20:42:06.057 に答える
1

これが目的かどうかはわかりませんが、通常、OSに依存しないJavaプログラムでパスに関連する処理を行う必要がある場合は、ファイルではなく文字列を使用してパスを渡します。次の2つを常に実行します。もの:

文字列パスを作成するときは常に/、ファイルセパレータとして使用します

文字列パスを使用してファイルを作成したり、ファイルをテキストとしてどこかに保存したりするときは常に、パスを使用する前に次の呼び出しを行います。

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);

これは、パスがローカルマシンで構築されているかどうか、またはローカルマシンでパスを使用する場合は、ネットワーク上の別のマシンから別のOSでパスが渡されているかどうかに関係なく、うまく機能するようです。ネットワークを介して異なるOS間でパスを渡すことを計画している場合は、独自のコードに一貫性があることに注意してください。

編集

うわー...どういうわけか私の答えが壊れて、コードのフォーマットが当初の意図どおりに機能しませんでした...

于 2012-05-31T20:16:55.197 に答える
0

java.util.File を拡張またはラップする独自の MyFile オブジェクトを作成します。次に、すべてのコードが java.io.File の代わりにこのオブジェクトを使用していることを確認してください。ここでは、OS チェックを実行し、メソッドを呼び出してファイル名をクリーンアップします。コードの残りの部分は「クリーン」になります。

于 2012-05-31T20:20:34.307 に答える
0

os-agnosticに戻す必要はありません。OS固有への変換は次のとおりです。

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()));
      }
    }
  });
}
于 2012-06-01T00:42:26.093 に答える