อะไรคือความแตกต่างระหว่าง __dirname และ ./ ใน node.js?


498

เมื่อการเขียนโปรแกรมใน Node.js และไฟล์อ้างอิงที่อยู่ในตำแหน่งที่สัมพันธ์กับไดเรกทอรีปัจจุบันของคุณมีเหตุผลใดบ้างที่จะใช้__dirnameตัวแปรแทนการใช้งานปกติ./? ฉันใช้. / ป่านนี้ในรหัสของฉันและเพิ่งค้นพบการดำรงอยู่ของ__dirnameและเป็นหลักต้องการทราบว่ามันจะฉลาดในการแปลง. / ของฉันเพื่อที่และถ้าเป็นเช่นนั้นทำไมมันจะเป็นความคิดที่ชาญฉลาด .


47
tl; dr: โดยพื้นฐานแล้วความแตกต่างคือ './' และ 'process.cwd ()' อ้างถึง dir ปัจจุบันของเทอร์มินัลที่เรียกใช้สคริปต์ในขณะที่ '__dirname' อ้างถึง dir ที่สคริปต์คือ เก็บไว้
Gui Imamura

1
ยกเว้นเมื่อภายในถูกนำมาใช้. requireภายในเส้นทางอยู่เสมอเมื่อเทียบกับไฟล์ที่มีการเรียกร้องให้require require
Govind Rai

คำตอบ:


814

ส่วนสำคัญ

ใน Node.js __dirnameเป็นไดเรกทอรีที่สคริปต์การดำเนินการอยู่ในปัจจุบันอยู่เสมอ ( ดูสิ่งนี้ ) ดังนั้นถ้าคุณพิมพ์__dirnameลงในค่าที่จะเป็น/d1/d2/myscript.js/d1/d2

โดยคมชัด.ช่วยให้คุณไดเรกทอรีที่คุณวิ่งnodeคำสั่งในหน้าต่าง terminal ของคุณ (เช่นไดเรกทอรีการทำงานของคุณ) เมื่อคุณใช้ห้องสมุดเหมือนและpath fsเทคนิคก็เริ่มออกเป็นไดเรกทอรีการทำงานของคุณ process.chdir()แต่สามารถเปลี่ยนการใช้

ยกเว้นในกรณีที่คุณใช้กับ. require()ภายในเส้นทางอยู่เสมอเมื่อเทียบกับไฟล์ที่มีการเรียกร้องให้requirerequire

ตัวอย่างเช่น...

สมมติว่าโครงสร้างไดเรกทอรีของคุณคือ

/dir1
  /dir2
    pathtest.js

และpathtest.jsมี

var path = require("path");
console.log(". = %s", path.resolve("."));
console.log("__dirname = %s", path.resolve(__dirname));

และคุณทำ

cd /dir1/dir2
node pathtest.js

คุณได้รับ

. = /dir1/dir2
__dirname = /dir1/dir2

ไดเรกทอรีการทำงานของคุณคือ/dir1/dir2สิ่งที่.แก้ไขได้ เนื่องจากpathtest.jsตั้งอยู่ใน/dir1/dir2นั่นคือสิ่งที่__dirnameจะแก้ไขเช่นกัน

อย่างไรก็ตามหากคุณเรียกใช้สคริปต์จาก /dir1

cd /dir1
node dir2/pathtest.js

คุณได้รับ

. = /dir1
__dirname = /dir1/dir2

ในกรณีดังกล่าวไดเรกทอรีทำงานของคุณเป็น/dir1สิ่งที่.แก้ไขได้ แต่__dirnameยังแก้ไข/dir1/dir2ได้

ใช้.ภายในrequire...

หากภายในdir2/pathtest.jsคุณมีrequireการโทรเข้ารวมไฟล์ภายในdir1ที่คุณจะเสมอทำ

require('../thefile')

เนื่องจากเส้นทางภายในrequireนั้นสัมพันธ์กับไฟล์ที่คุณเรียกใช้อยู่เสมอ มันไม่มีส่วนเกี่ยวข้องกับไดเรกทอรีทำงานของคุณ


38
IMO คำอธิบายนี้ค่อนข้างชัดเจนกว่าคำตอบที่ยอมรับ (คุณรู้ว่า "ไดเรกทอรีปัจจุบัน" ค่อนข้างคลุมเครืออยู่ตรงนั้น)
จุติลง

5
ฉันเห็นด้วย. ฉันจะเปลี่ยนคำตอบที่ยอมรับ โปรดจำไว้ว่าคำตอบนี้ถูกเพิ่มเติม 2.5 ปีหลังจากคำตอบเดิมและฉันเพิ่งสังเกตเห็นตอนนี้ (อีก 2 ปีต่อมา) :) มาสายดีกว่าไม่มาเลย!
thisissami

14
เป็นที่น่าสังเกตว่า./ไม่เสมอไปที่ไดเรกทอรีที่โหนดเปิดตัว มันเริ่มต้นจากวิธีการที่ process.chdir()แต่สามารถเปลี่ยนแปลงได้ผ่านทาง ดังนั้นจึง./เป็นไดเรกทอรีการทำงานปัจจุบันเสมอซึ่งโดยปกติจะเป็นไดเรกทอรีไดรฟ์ที่เปิดตัวยกเว้นรหัสของคุณจะเปลี่ยนไดเรกทอรีการทำงานอย่างชัดเจน
gilly3

3
ฉันสับสนเล็กน้อยเกี่ยวกับการใช้ ข้างในต้องการส่วนหนึ่งถ้าเส้นทางภายในต้องการสัมพันธ์กับไฟล์ที่คุณกำลังเรียกอยู่เสมอไม่ควรใช้พา ธ ('../ thefile') แทนการต้องการ ('../ dir1 / thefile')? ฉันคิดว่า .. นำตำแหน่งปัจจุบันของเส้นทางกลับมาหนึ่งระดับจาก dir2 ถึง dir1 แล้ว คุณยังต้องใส่ dir1 ในเส้นทางหรือไม่เข้าใจหรือไม่?
andromada

1
และคุณจะทำอย่างไรถ้าคุณต้องการใช้../someDirในบางสคริปต์และคุณจะเรียกใช้คำสั่งจากโฟลเดอร์อื่น?
cbdeveloper

154

./อ้างถึงไดเรกทอรีการทำงานปัจจุบันยกเว้นในrequire()ฟังก์ชั่น เมื่อใช้require()งานจะแปล./เป็นไดเรกทอรีของไฟล์ปัจจุบันที่เรียกว่า __dirnameเป็นไดเรกทอรีของไฟล์ปัจจุบันเสมอ

ตัวอย่างเช่นด้วยโครงสร้างไฟล์ต่อไปนี้

/home/user/dir/files/config.json

{
  "hello": "world"
}

/home/user/dir/files/somefile.txt

text file

/home/user/dir/dir.js

var fs = require('fs');

console.log(require('./files/config.json'));
console.log(fs.readFileSync('./files/somefile.txt', 'utf8'));

ถ้าฉันcdเข้า/home/user/dirและวิ่งnode dir.jsฉันจะได้รับ

{ hello: 'world' }
text file

แต่เมื่อฉันเรียกใช้สคริปต์เดียวกันจาก/home/user/ฉันได้รับ

{ hello: 'world' }

Error: ENOENT, no such file or directory './files/somefile.txt'
    at Object.openSync (fs.js:228:18)
    at Object.readFileSync (fs.js:119:15)
    at Object.<anonymous> (/home/user/dir/dir.js:4:16)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

การใช้./ทำงานร่วมกับแต่ไม่ได้สำหรับrequire fs.readFileSyncนั่นเป็นเพราะสำหรับfs.readFileSync, ./แปลเป็น CWD (ในกรณีนี้/home/user/) และ/home/user/files/somefile.txtไม่มีอยู่จริง


โอ้ฉันคิดว่า __ ชื่อเล่นเป็นไดเรกทอรีการทำงานปัจจุบัน ... ขอบคุณสำหรับคำชี้แจง!
thisissami

มีวิธีการอ้างอิงไดเรกทอรีทำงานของแอพด้วย fs หรือไม่? ตัวอย่างเช่นฉันพยายามที่จะโหลดไฟล์จากไดเรกทอรีทำงาน/moviesแต่เนื่องจากโมดูลของฉันอยู่ในแฟ้ม/custom_modules/, __dirnameพยายามที่จะคว้าภาพยนตร์จาก/custom_modules/movies

2
คุณสามารถใช้หรือ./ process.cwd()ดูnodejs.org/api/process.html#process_process_cwd
fent

น่าสังเกตว่าไม่ใช่ความคิดที่ดีที่จะใช้ __dirname มากกว่า. / in ต้องมี statement เพราะถึงแม้ว่ามันจะทำงานเหมือนกันใน node มันสามารถทำให้เกิดปัญหากับ browserify builds สำหรับแพ็คเกจที่หลีกเลี่ยงได้ง่าย
Jed Watson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.