2018/04/01

Path Issue

今天來聊聊路徑,這幾天寫 python 要執行 cronjob 的時候發現一件有趣的事情,來看程式碼

# -*- coding: utf-8 -*-


def file_get_contents(file_path):
    with open(file_path, 'r') as the_file:
        return the_file.read().strip()


print(file_get_contents('logs/chan.log'))

我們在 logs 目錄下建一個檔案叫 chan.log,裡面只有 hello world 字串,接下來我們在同等目錄下執行程式

/var/www/python/ $ python path.py
hello world

我們得到正確的結果,但假設要寫 cronjob 不會這樣下指令,我們會下 /usr/bin/python /var/www/python/path.py,我們將目錄切換到 /tmp 再來看看結果

/var/www/python/ $ cd /tmp
/tmp $ /usr/bin/python /var/www/python/path.py
Traceback (most recent call last):
  File "/var/www/python/path.py", line 9, in <module>
    print(file_get_contents('logs/chan.log'))
  File "/var/www/python/path.py", line 5, in file_get_contents
    with open(file_path, 'r') as the_file:
IOError: [Errno 2] No such file or directory: 'logs/chan.log'

我們得到了找不到目錄或檔案的訊息,python 在執行時會因為不同的位置得不到相對路徑的結果,可以說好也可以說不好,引用的路徑本來就該相對嚴格些,不好在有時候一些簡單的東西想偷懶都不行了,來修正程式碼

# -*- coding: utf-8 -*-

import os


def file_get_contents(file_path):
    real_path = os.path.join(os.path.dirname(__file__), file_path)
    with open(real_path, 'r') as the_file:
        return the_file.read().strip()


print(file_get_contents('logs/chan.log'))

再次執行

/tmp $ /usr/bin/python /var/www/python/path.py 
hello world

得到正確的結果了,讓我們來看看 node.js

const fs = require('fs');

const content = fs.readFileSync('logs/chan.log').toString().trim();

console.log(content);
/var/www/nodejs $ node path.js
hello world
/var/www/nodejs $ cd /tmp
/tmp $ /usr/bin/node /var/www/nodejs/path.js 
fs.js:646
  return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                 ^

Error: ENOENT: no such file or directory, open 'logs/chan.log'
    at Object.fs.openSync (fs.js:646:18)
    at Object.fs.readFileSync (fs.js:551:33)
    at Object.<anonymous> (/var/www/nodejs/path.js:3:20)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)

沒想到 node.js 的認定跟 python 是一樣的呢,來修改程式碼

const fs = require('fs');
const path = require('path');

const fileGetContents = (filePath) => {
    const realPath = path.join(__dirname, filePath);

    return fs.readFileSync(realPath).toString().trim();
};

console.log(fileGetContents('logs/chan.log'));
/tmp $ /usr/bin/node /var/www/nodejs/path.js 
hello world

得到正確的結果了,我們來看看 PHP

<?php

echo trim(file_get_contents('logs/chan.log')), PHP_EOL;
/var/www/php $ php path.php 
hello world

PHP 一行就寫完了,難怪是這個世界上最好的語言(lol)

/tmp $ /usr/bin/php /var/www/php/path.php 
PHP Warning:  file_get_contents(logs/chan.log): failed to open stream: No such file or directory in /var/www/php/path.php on line 3

OK,事實上只要離開了相對位置,三個語言遇到的情況是一樣的,來修改程式碼

<?php

echo trim(file_get_contents(__DIR__.'/logs/chan.log')), PHP_EOL;
/tmp $ /usr/bin/php /var/www/php/path.php 
hello world

什麼,PHP 加一個 __DIR__ 就搞定了,你還在跟我爭 PHP 是不是世界上最好的語言 (lol)?

來總結一下,其實在這三個語言裡用類似 include 語法內部引入檔案時是不會有問題的,例如說 include ../file.php;,只是我自己習慣還是會 include __DIR__.'/../file.php'; 去引用,這樣會更萬無一失

沒有留言: