見出し画像

プログラマー必見!!相対パスのエラーで悩んでいる方向けの特効薬が出来ました!!

プログラミングは相対パスを使ったほうが便利、と習ったそこのあなた!!相対パスによるエラーに巻き込まれたことはありませんか?コマンドの実行場所がちょっとでも異なると、エラーで動かなくなった、という経験、ありませんか?

そんなあなたでも、次のコードを使ってみれば、もしかしたら作業が楽になりますよ?エラーが起きない分、戸惑う時間を節約できるかも知れません!


絶対パスと相対パスのいいとこ取りをしよう!

絶対パス…
~/media/owner/Elements/自作/超越数、のように、対象のファイルの場所を明示するパスのこと。パスの名前がはっきりするので、どこでコードを実行しても、そのパスを必ず実行する。

相対パス…
/自作/超越数、のように、コマンドを実行する場所から見てファイルがどこにあるのかを示すパスのこと。フォルダごと自分のコードと対象ファイルを移動させる場合、相対パスなら、関係性が変わらないので、いちいちコードを直さなくて済む。

絶対パスと相対パスは、このように、それぞれ特徴があります。パスを固定したい場合は絶対パス、いろんなところに応用したい場合は相対パスが便利です。しかし、ここで問題です。コマンドを好きな場所で実行し、実行コードのフォルダを頻繁に移したい場合はどうでしょうか?

絶対パスの場合、実行コードのフォルダを動かすと、途端にエラーがでます。いちいちコードを書き換えないといけません。相対パスの場合、コマンドを実行する場所を間違えると、対象ファイルが認知されなくなってしまいます。両方を解決する方法は何なのでしょうか?それは、

スクリプトのあるディレクトリを基準にしたパスを使用すること

です。

実行コードから見て、参照したいファイルがどこにあるか、というのが分かればいいわけです。~/media/owner/Elements/自作/超越数/超越数.pyを実行したい場合、超越数.pyの入っているフォルダの絶対パスは今示した通りです。

『(そのフォルダの中の)変換前』フォルダの画像を『(そのフォルダの中の)変換後』フォルダにレンダリングする、というのが目標だとします。『(そのフォルダの中の)』という部分を作るのが、Pythonでいう`__file__`関数なのです。以下で見本を見せます。

python
import os

def main():
    script_dir = os.path.dirname(os.path.abspath(__file__))  # スクリプトのディレクトリを取得
    input_dir = os.path.join(script_dir, '変換前')
    output_dir = os.path.join(script_dir, '変換後')

    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    for filename in os.listdir(input_dir):
        if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff')):
            input_image_path = os.path.join(input_dir, filename)
            output_image_path = os.path.join(output_dir, filename)
            process_image(input_image_path, output_image_path)
            print(f'Processed {input_image_path} -> {output_image_path}')

os.path⇛パス関数
abspath…絶対パスを返す
dirname…直属のフォルダ名(ディレクトリ名)を返す
join…パス名を結合させる
os.makedirs⇛ディレクトリを作る
os.listdir⇛ファイルやディレクトリの一覧を得る

⇑の一覧は、import osでosモジュールをインストールしないと使えません。

ここで重要なのは script_dir = os.path.dirname(os.path.abspath(__file__)) の部分で、フォルダ名=(((実行コードのファイルパス)⇛の絶対パス)⇛の所属するフォルダ)なのです。()の内側から順番に読み解いていきます。あとは、このフォルダ名を基準に実行したいファイルを参照するだけです。

### この方法の利点

- **一貫性**: スクリプトの位置に依存するので、他のディレクトリから実行しても、スクリプトが期待するディレクトリを正しく参照できます。
- **移植性**: プロジェクトが異なる環境に移動しても、同じディレクトリ構造内で動作します。
- **明示的**: 使用されるパスがどうなるかが明確なので、コードの可読性と保守性が向上します。

この方法は、スクリプトファイルがどこにいても確実にその位置からの相対的な場所を使用するため、相対パスの利便性と絶対パスの安定性を両立した方法となります。だからこそややこしくなるのですが。。。

色んなコードで例を見てみよう(コピペ推奨します)!!

### Fortran

Fortranには標準でファイルパス操作がないため、外部ライブラリやシステムコールの利用が必要です。以下は擬似的な例:

fortran
! Fortran の場合、システムコールを使用するか、外部ライブラリを必要とする

### C++

cpp
#include <iostream>
#include <filesystem>

std::filesystem::path get_full_path(const std::string& relative_path) {
    auto script_dir = std::filesystem::current_path();
    return script_dir / relative_path;  // 現在のディレクトリを使用
}

### Rust

rust
use std::env;
use std::path::PathBuf;

fn get_full_path(relative_path: &str) -> PathBuf {
    let script_dir = env::current_dir().unwrap();
    script_dir.join(relative_path)
}

### Go

go
package main

import (
	"os"
	"path/filepath"
)

func getFullPath(relativePath string) (string, error) {
	scriptDir, err := os.Getwd()
	if err != nil {
		return "", err
	}
	return filepath.Join(scriptDir, relativePath), nil
}

### Julia

julia
function get_full_path(relative_path::String)
    script_dir = @__DIR__
    return joinpath(script_dir, relative_path)
end

### Swift

swift
import Foundation

func getFullPath(relativePath: String) -> String {
    let scriptDir = FileManager.default.currentDirectoryPath
    let fullPath = (scriptDir as NSString).appendingPathComponent(relativePath)
    return fullPath
}

### Mojo

**(現時点での情報がありませんが、Pythonライクなアプローチが予想されます)**

python
# Glyphs are expected to be similar to Python's

### C#

csharp
using System.IO;

string GetFullPath(string relativePath) {
    string scriptDir = Directory.GetCurrentDirectory();
    return Path.Combine(scriptDir, relativePath);
}

### Java

java
import java.nio.file.Paths;

public static String getFullPath(String relativePath) {
    String scriptDir = Paths.get("").toAbsolutePath().toString();
    return Paths.get(scriptDir, relativePath).toString();
}

### Kotlin

kotlin
import java.nio.file.Paths

fun getFullPath(relativePath: String): String {
    val scriptDir = Paths.get("").toAbsolutePath().toString()
    return Paths.get(scriptDir, relativePath).toString()
}

### Plutus (Haskell)

**(Plutusとしては直接的なファイル操作は想起されないため省略)**

### Elixir

elixir
def get_full_path(relative_path) do
    script_dir = System.cwd()
    Path.join(script_dir, relative_path)
end

### Python

python
import os

def get_full_path(relative_path):
    script_dir = os.path.dirname(os.path.abspath(__file__))
    return os.path.join(script_dir, relative_path)

### JavaScript (Node.js)

javascript
const path = require('path');

function getFullPath(relativePath) {
    const scriptDir = __dirname;
    return path.join(scriptDir, relativePath);
}

### PHP

php
function getFullPath($relativePath) {
    $scriptDir = __DIR__;
    return realpath($scriptDir . DIRECTORY_SEPARATOR . $relativePath);
}

### Ruby

ruby
def get_full_path(relative_path)
    script_dir = File.dirname(__FILE__)
    File.join(script_dir, relative_path)
end

### Perl

perl
use File::Spec;
use Cwd 'abs_path';

sub get_full_path {
    my ($relative_path) = @_;
    my $script_dir = abs_path($0);
    return File::Spec->catfile($script_dir, $relative_path);
}

### BeanShell

java
import java.nio.file.Paths;

public String getFullPath(String relativePath) {
    String scriptDir = Paths.get(".").toAbsolutePath().normalize().toString();
    return Paths.get(scriptDir, relativePath).toString();
}

### Mathematica

mathematica
GetFullPath[relativePath_String] := 
 FileNameJoin[{NotebookDirectory[], relativePath}]

### Phoenix (Elixirのフレームワーク)

elixir
def get_full_path(relative_path) do
    script_dir = System.cwd()
    Path.join(script_dir, relative_path)
end

### Yesod (HaskellのWebフレームワーク)

**(通常のHaskellとしてのファイル操作を使用)**

### Servant (HaskellのWebフレームワーク)

**(通常のHaskellとしてのファイル操作を使用)**

### Unity (C#のゲーム開発プラットフォーム)

csharp
using System.IO;

string GetFullPath(string relativePath) {
    string scriptDir = Application.dataPath; 
    return Path.Combine(scriptDir, relativePath);
}

### LibreOffice Basic

basic
Function GetFullPath(relativePath As String) As String
    Dim scriptDir As String
    scriptDir = ThisComponent.getURL()
    scriptDir = ConvertFromURL(scriptDir)
    GetFullPath = scriptDir & relativePath
End Function

### VBA

vba
Function GetFullPath(relativePath As String) As String
    Dim scriptDir As String
    scriptDir = ThisWorkbook.Path
    GetFullPath = scriptDir & Application.PathSeparator & relativePath
End Function

### WordPress (PHP)

php
function getFullPath($relativePath) {
    $scriptDir = plugin_dir_path(__FILE__);
    return $scriptDir . $relativePath;
}

### Lua

lua
local function getFullPath(relativePath)
    local scriptDir = debug.getinfo(1).source:match("@?(.*/)")
    return scriptDir .. relativePath
end

これらの実装はそれぞれの言語やフレームワークの特性を活かしています。欠点や不具合を避け、確実に絶対パスが得られるように、提供されたAPIや関数を活用して実装しています。すべての例が実際の環境で動作するわけではないため、特に一部の環境に合わせた修正が必要です。

まとめ

Javaのベテランシステムエンジニアには、AIプログラミングの時代、こういうのは日本では意味ない、と忠告を受けました。ですが、私は、クリエイター側の立場として、半信半疑のスタンスをとろうかと思ってます。というのも、中国で計算メモリの消費を抑えたAIが出来た、という噂を聞いてます。

その原理がわからないのですが、もしこういうことの積み重ねをしているのであれば、役に立つ可能性はあるかもしれない、と読んでます。色々実験してみないと、これが当たるのか外れるのか、分からないので、選択肢を増やして試してみたいところです。人狼ゲームのように、保険はかけたいですね。

いいなと思ったら応援しよう!

Ubuntu初心者である漫画村の弟子
note限定で、みんなのフォトギャラリーに無償で大量の画像を順次UPする予定です!ですが、ペタバイトクラスで供給するとなると、容量が一杯になり、皆さんのチップが必要となります!これからも画像をどんどん供給していくので、チップをお願いします!