วิธีจับไม่มีไฟล์สำหรับ fs.readFileSync ()


135

ภายใน node.js readFile ()แสดงวิธีการจับข้อผิดพลาดอย่างไรก็ตามไม่มีข้อคิดเห็นสำหรับฟังก์ชัน readFileSync ()เกี่ยวกับการจัดการข้อผิดพลาด เช่นถ้าฉันพยายามที่จะใช้ readFileSync () Error: ENOENT, no such file or directoryเมื่อไม่มีแฟ้มที่ฉันได้รับข้อผิดพลาด

ฉันจะจับข้อยกเว้นที่ถูกโยนได้อย่างไร? doco ไม่ได้ระบุว่ามีข้อยกเว้นใดบ้างที่ถูกโยนดังนั้นฉันจึงไม่รู้ว่าฉันต้องจับข้อยกเว้นอะไรบ้าง ฉันควรทราบว่าฉันไม่ชอบรูปแบบคำสั่ง try / catch แบบ 'จับทุกข้อยกเว้นที่เป็นไปได้' ทั่วไป ในกรณีนี้ฉันต้องการตรวจจับข้อยกเว้นเฉพาะที่เกิดขึ้นเมื่อไม่มีไฟล์และฉันพยายามดำเนินการ readFileSync

โปรดทราบว่าฉันกำลังใช้งานฟังก์ชั่นซิงค์เมื่อเริ่มต้นเท่านั้นก่อนที่จะให้บริการพยายามเชื่อมต่อดังนั้นจึงไม่จำเป็นต้องแสดงความคิดเห็นว่าฉันไม่ควรใช้ฟังก์ชันการซิงค์ :-)


1
คุณยังfs.existsSync()สามารถใช้ได้ตามที่เห็นในคำตอบใหม่ของฉัน
Francisco Presencia

คำตอบ:


206

โดยทั่วไปจะfs.readFileSyncแสดงข้อผิดพลาดเมื่อไม่พบไฟล์ ข้อผิดพลาดนี้มาจากErrorต้นแบบและถูกโยนโดยใช้throwดังนั้นวิธีเดียวที่จะจับคือtry / catchบล็อก:

var fileContents;
try {
  fileContents = fs.readFileSync('foo.bar');
} catch (err) {
  // Here you get the error when the file was not found,
  // but you also get any other error
}

น่าเสียดายที่คุณไม่สามารถตรวจพบข้อผิดพลาดใดที่เกิดขึ้นเพียงแค่ดูที่ห่วงโซ่ต้นแบบ:

if (err instanceof Error)

เป็นวิธีที่ดีที่สุดที่คุณสามารถทำได้และจะเป็นจริงสำหรับข้อผิดพลาดส่วนใหญ่ (ถ้าไม่ใช่ทั้งหมด) ดังนั้นฉันขอแนะนำให้คุณไปกับcodeสถานที่ให้บริการและตรวจสอบมูลค่า:

if (err.code === 'ENOENT') {
  console.log('File not found!');
} else {
  throw err;
}

ด้วยวิธีนี้คุณจะจัดการเฉพาะข้อผิดพลาดนี้และโยนข้อผิดพลาดอื่น ๆ ทั้งหมดอีกครั้ง

หรือคุณยังสามารถเข้าถึงmessageคุณสมบัติของข้อผิดพลาดเพื่อตรวจสอบข้อความแสดงข้อผิดพลาดโดยละเอียดซึ่งในกรณีนี้คือ:

ENOENT, no such file or directory 'foo.bar'

หวังว่านี่จะช่วยได้


1
ขอบคุณนั่นคือข้อมูลที่ฉันกำลังค้นหา ฉันแค่สันนิษฐานว่ามันน่าจะเป็นข้อผิดพลาดบางประเภท ฉันเพิ่งรู้ว่าฉันเข้าใจผิดว่า try / catch ทำงานอย่างไรฉันคิดว่าคุณสามารถตรวจจับประเภทข้อผิดพลาดที่เฉพาะเจาะจงได้ (a la java) ขอบคุณสำหรับข้อมูล Golo :-)
Metalskin

2
นอกจากนี้EACCESควรตรวจสอบรหัสในคำสั่ง if สำหรับกรณีที่มีไฟล์อยู่ แต่ไม่สามารถอ่านได้เนื่องจากไม่มีสิทธิ์
Gergely Toth

21

ฉันชอบวิธีจัดการนี้มากกว่า คุณสามารถตรวจสอบว่ามีไฟล์พร้อมกันหรือไม่:

var file = 'info.json';
var content = '';

// Check that the file exists locally
if(!fs.existsSync(file)) {
  console.log("File not found");
}

// The file *does* exist
else {
  // Read the file and do anything you want
  content = fs.readFileSync(file, 'utf-8');
}

หมายเหตุ: หากโปรแกรมของคุณลบไฟล์ด้วยแสดงว่ามีเงื่อนไขการแข่งขันตามที่ระบุไว้ในความคิดเห็น อย่างไรก็ตามหากคุณเขียนหรือเขียนทับไฟล์เท่านั้นโดยไม่ต้องลบไฟล์เหล่านี้ก็ใช้ได้โดยสิ้นเชิง


2
ตอนนี้ fs.existsSync ไม่ได้เลิกใช้งานอีกต่อไป : "โปรดทราบว่า fs.exists () เลิกใช้งานแล้ว แต่ fs.existsSync () ไม่ใช่"
falkodev

17
ไม่ดีขึ้นเลย. จะเกิดอะไรขึ้นถ้าไฟล์ถูกลบออกจากดิสก์ระหว่างการเรียกมีอยู่ซิงค์และ readFileSync ตอนนี้โค้ดของคุณมีเงื่อนไขการแข่งขันที่รอให้เกิดขึ้น ...
tkarls

2
@tkarls ใช่ถูกต้องทั้งหมดที่เขียนเมื่อปี 2015 ตอนที่ฉันยังเรียนรู้ Node.js และมีเงื่อนไขการแข่งขัน อย่างไรก็ตามสองสิ่งที่ควรทราบ: ความคล้ายคลึงกันของเงื่อนไขการแข่งขันนี้มีน้อยมากจนสามารถละเลยได้โดยทั่วไปและประการที่สองและแทนที่อย่างแรกคือฉันจะใช้ try / catch กับ async / await ในปัจจุบันทำให้โค้ดของฉันมีความยืดหยุ่นมากขึ้นในการ ข้อยกเว้น "อื่น ๆ " (เนื่องจากโหนดเป็นมิตรกับข้อยกเว้น)
Francisco Presencia

1
เงื่อนไขการแข่งขันไม่สำคัญจนกว่าจะเป็นเช่นนั้น คำตอบเช่นนี้คือสาเหตุที่ซอฟต์แวร์ถูกกำจัดข้อผิดพลาดทำไมคุณต้องรีสตาร์ทคอมพิวเตอร์บ่อยครั้งทำไมจึงมีช่องโหว่ด้านความปลอดภัยมากมาย ฯลฯ Stack Overflow ควรมีการตั้งค่าสถานะสำหรับคำตอบที่อาจเป็นอันตราย
Jonathan Tran

ความคิดเห็นอื่นอีก N ปีต่อมาหลังจากเรียนรู้มากขึ้น (เพิ่มบันทึกในคำตอบ) สิ่งนี้ใช้ได้ดีในบริบทของโปรแกรมระบบไฟล์แบบเขียนอย่างเดียว แต่ตามที่ระบุไว้ว่าไฟล์สามารถลบออกได้หรือไม่ซึ่งมีเงื่อนไขการแข่งขันและไม่ใช่รหัสที่ฉันจะเขียนในปัจจุบัน (โดยเฉพาะเนื่องจาก Sync!) ฉันได้เขียนแพ็คเกจfilesด้วยทั้งหมดที่ฉันได้เรียนรู้ที่จะทำให้ async และลอง / จับง่ายขึ้น
Francisco Presencia

11

คุณต้องจับข้อผิดพลาดแล้วตรวจสอบว่าเป็นข้อผิดพลาดประเภทใด

try {
  var data = fs.readFileSync(...)
} catch (err) {
  // If the type is not what you want, then just throw the error again.
  if (err.code !== 'ENOENT') throw err;

  // Handle a file-not-found error
}

... ทำให้ 'โยนผิด;'
drudru

มีวิธีใดบ้างที่จะตรวจจับข้อผิดพลาดเดียวกันกับฟังก์ชันเวอร์ชันที่ไม่ได้ซิงค์
Ki Jéy

1
@ KiJéyรหัส Async ส่งผ่านข้อผิดพลาดเป็นอาร์กิวเมนต์แรกของการเรียกกลับดังนั้นหากคุณตรวจสอบว่าคุณได้รับพฤติกรรมเดียวกัน
loganfsmyth

4

ฉันใช้แลมด้าที่เรียกใช้ทันทีสำหรับสถานการณ์เหล่านี้:

const config = (() => {
  try {
    return JSON.parse(fs.readFileSync('config.json'));
  } catch (error) {
    return {};
  }
})();

async รุ่น:

const config = await (async () => {
  try {
    return JSON.parse(await fs.readFileAsync('config.json'));
  } catch (error) {
    return {};
  }
})();

คุณอาจต้องการเพิ่มในโพสต์ของคุณว่าโซลูชันของคุณใช้สำหรับ ECMAScript 6 ณ วันที่ 01/01/18 ไม่มีการสนับสนุนจาก IE ซึ่งครอบคลุมการใช้งานเบราว์เซอร์ประมาณ 77% ( caniuse.com/#feat=arrow-functions ) ฉันสงสัยว่าคุณจะรองรับผู้ใช้ IE ได้อย่างไร
Metalskin

2
@Metalskin Webpack + Babel. อย่างไรก็ตามfsเป็นโมดูลโหนด
sdgfsdh

อ่าฉันไม่ได้ติดต่อกับโหนดฉันสงสัยว่าโหนดไม่รองรับ ES6 เมื่อฉันถามคำถาม (อาจผิด) ลืมไปเลยว่านี่เป็นคำถามเกี่ยวกับโหนดเช่นกัน ;-)
Metalskin

กำลังอัปเดตสิ่งนี้ ... fs.readFileAsync()อยู่ในขณะนี้fs.readFile() และไม่ควรใส่ฟังก์ชัน async ไว้ใน try / catch ใน node.js การลอง / จับจะไม่ได้รับข้อผิดพลาดเนื่องจากเป็นแบบ async แทนที่จะส่งข้อผิดพลาดในการโทรกลับและจัดการที่นั่น: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); from: nodejs.org/dist/latest-v12.x/docs/api/…
KH B

ฉันเชื่อว่าการลองจับจะถูกเรียกหากคำสัญญาถูกปฏิเสธและคุณกำลังรอคำสัญญา
sdgfsdh

0

ลองใช้Asyncแทนเพื่อหลีกเลี่ยงการบล็อกเธรดเดียวที่คุณมีกับ NodeJS ตรวจสอบตัวอย่างนี้:

const util = require('util');
const fs = require('fs');
const path = require('path');
const readFileAsync = util.promisify(fs.readFile);

const readContentFile = async (filePath) => {
  // Eureka, you are using good code practices here!
  const content = await readFileAsync(path.join(__dirname, filePath), {
    encoding: 'utf8'
  })
  return content;
}

ในภายหลังสามารถใช้ฟังก์ชัน async นี้ร่วมกับ try / catch จากฟังก์ชันอื่น ๆ :

const anyOtherFun = async () => {
  try {
    const fileContent = await readContentFile('my-file.txt');
  } catch (err) {
    // Here you get the error when the file was not found,
    // but you also get any other error
  }
}

Happy Coding!


0

ไม่สามารถใช้กลไก JavaScript try … catch เพื่อสกัดกั้นข้อผิดพลาดที่สร้างขึ้นโดย API แบบอะซิงโครนัส ข้อผิดพลาดทั่วไปสำหรับผู้เริ่มต้นคือพยายามใช้การโยนภายในการเรียกกลับครั้งแรกที่ผิดพลาด:

// THIS WILL NOT WORK:
const fs = require('fs');

try {
  fs.readFile('/some/file/that/does-not-exist', (err, data) => {
    // Mistaken assumption: throwing here...
    if (err) {
      throw err;
    }
  });
} catch (err) {
  // This will not catch the throw!
  console.error(err);
}

สิ่งนี้จะไม่ทำงานเนื่องจากฟังก์ชันการโทรกลับส่งไปยัง fs.readFile () ถูกเรียกแบบอะซิงโครนัส เมื่อมีการโทรกลับรหัสรอบ ๆ รวมทั้ง try … catch block จะออกไปแล้ว การแสดงข้อผิดพลาดภายในการเรียกกลับอาจทำให้กระบวนการ Node.js ขัดข้องได้ในกรณีส่วนใหญ่ หากโดเมนถูกเปิดใช้งานหรือมีการลงทะเบียนตัวจัดการกับ process.on ('uncaughtException') ข้อผิดพลาดดังกล่าวอาจถูกดักจับได้

อ้างอิง: https://nodejs.org/api/errors.html

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.