Jak przechwycić żaden plik dla fs.readFileSync ()?

138

W module node.js readFile () pokazuje, jak przechwycić błąd, jednak funkcja readFileSync () nie zawiera komentarza dotyczącego obsługi błędów. W związku z tym, jeśli spróbuję użyć readFileSync (), gdy nie ma pliku, pojawia się błąd Error: ENOENT, no such file or directory.

Jak uchwycić zgłaszany wyjątek? Dokument doco nie określa, jakie wyjątki są generowane, więc nie wiem, jakie wyjątki muszę przechwycić. Powinienem zauważyć, że nie podoba mi się ogólny styl instrukcji try / catch typu „złap każdy możliwy wyjątek”. W tym przypadku chcę złapać określony wyjątek, który występuje, gdy plik nie istnieje i próbuję wykonać readFileSync.

Pamiętaj, że wykonuję funkcje synchronizacji tylko podczas uruchamiania przed obsługą prób połączenia, więc komentarze, że nie powinienem używać funkcji synchronizacji, nie są wymagane :-)

Metalskin
źródło
1
Możesz również użyć tego, fs.existsSync()co widać w mojej nowej odpowiedzi
Francisco Presencia

Odpowiedzi:

213

Zasadniczo fs.readFileSynczgłasza błąd, gdy plik nie zostanie znaleziony. Ten błąd pochodzi z Errorprototypu i został wyrzucony za pomocą throw, stąd jedynym sposobem na złapanie jest try / catchblok:

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
}

Niestety nie możesz wykryć, który błąd został zgłoszony, po prostu patrząc na jego łańcuch prototypów:

if (err instanceof Error)

to najlepsze, co możesz zrobić i będzie to prawdą w przypadku większości (jeśli nie wszystkich) błędów. Dlatego proponuję udać się z codenieruchomością i sprawdzić jej wartość:

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

W ten sposób zajmujesz się tylko tym konkretnym błędem i ponownie zgłaszasz wszystkie inne błędy.

Alternatywnie możesz również uzyskać dostęp do messagewłaściwości błędu, aby zweryfikować szczegółowy komunikat o błędzie, którym w tym przypadku jest:

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

Mam nadzieję że to pomoże.

Golo Roden
źródło
1
Dzięki, to jest informacja, której szukałem. Po prostu przypuszczałem, że będzie to szczególny rodzaj błędu. Właśnie zdałem sobie sprawę, że źle zrozumiałem, jak działa try / catch, pomyślałem, że możesz złapać określony typ błędu (a la java). Dzięki za informację Golo. :-)
Metalskin
2
Również EACCESkod należy sprawdzać w instrukcji if w przypadku, gdy plik jest tam, ale nie można odczytać z powodu braku uprawnień
Gergely Toth
21

Wolę ten sposób radzenia sobie z tym. Możesz sprawdzić, czy plik istnieje synchronicznie:

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

Uwaga: jeśli twój program usuwa również pliki, jest to sytuacja wyścigu, jak zaznaczono w komentarzach. Jeśli jednak piszesz lub nadpisujesz tylko pliki, bez ich usuwania, to jest to całkowicie w porządku.

Francisco Presencia
źródło
2
teraz fs.existsSync nie jest już przestarzałe : „Zauważ, że fs.exists () jest przestarzałe, ale fs.existsSync () nie.”
falkodev
19
Wcale nie lepiej. Co się stanie, jeśli plik zostanie usunięty z dysku między wywołaniem existSync i readFileSync? Twój kod ma teraz wbudowany stan wyścigu, który czeka na
wystąpienie
2
@tkarls tak, to jest całkowicie słuszne, zostało to napisane w 2015 roku, kiedy jeszcze uczyłem się Node.js i ma stan wyścigu. Jednak dwie rzeczy, na które należy zwrócić uwagę: podobieństwo tego stanu wyścigu jest tak minimalne, że można go w zasadzie zignorować, a druga i zastępująca pierwszą polega na tym, że używałbym obecnie try / catch z async / await, dzięki czemu mój kod jest bardziej elastyczny, aby „inne” wyjątki (ponieważ Node jest przyjazny dla wyjątków).
Francisco Presencia
2
Warunki wyścigu nie mają znaczenia, dopóki nie. Takie odpowiedzi wyjaśniają, dlaczego oprogramowanie jest tak pełne błędów, dlaczego tak często musisz ponownie uruchamiać komputer, dlaczego jest tak wiele luk w zabezpieczeniach itp. Itp. Przepełnienie stosu powinno mieć flagę dla potencjalnie szkodliwych odpowiedzi.
Jonathan Tran
Kolejny komentarz N lat później, po tym, jak dowiedziałem się więcej (dodałem notatkę w odpowiedzi). Jest to całkowicie w porządku w kontekście programu systemu plików tylko do zapisu, ale jak zauważono, jeśli pliki można również usunąć, ma to stan wyścigu i nie jest to kod, który będę pisał obecnie (szczególnie z powodu tej synchronizacji!). Napisałem również pakiet filesze wszystkim, czego się nauczyłem, aby ułatwić asynchronizację i try / catch.
Francisco Presencia,
12

Musisz wyłapać błąd, a następnie sprawdzić, jakiego rodzaju jest to błąd.

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
}
loganfsmyth
źródło
... spraw, aby 'błąd rzutów;'
drudru 16.07.15
Czy jest jakiś sposób, aby złapać ten sam błąd w niezsynchronizowanej wersji funkcji?
Ki Jéy
1
Kod @ KiJéy Async przekazuje błąd jako pierwszy argument wywołania zwrotnego, więc jeśli sprawdzisz, otrzymasz takie samo zachowanie.
loganfsmyth
4

Używam natychmiast wywołanej lambdy w następujących scenariuszach:

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

async wersja:

const config = await (async () => {
  try {
    return JSON.parse(await fs.readFileAsync('config.json'));
  } catch (error) {
    return {};
  }
})();
sdgfsdh
źródło
Możesz dodać do swojego posta, że ​​Twoje rozwiązanie jest dla ECMAScript 6. Od 01/01/18 IE nie ma wsparcia ze strony IE z około 77% pokryciem użytkowania przeglądarki ( caniuse.com/#feat=arrow-functions ). Jestem ciekawy, jak obsłużysz użytkowników IE?
Metalskin
2
@Metalskin Webpack + Babel. Jednak fsjest to moduł węzła
sdgfsdh
Ahh, nie mam kontaktu z węzłem, podejrzewam, że ten węzeł nie obsługiwał ES6, kiedy zadałem pytanie (może być źle). Trochę zapomniałem, że to też było pytanie o węzeł ;-)
Metalskin
aktualizowanie tego ... fs.readFileAsync()jest teraz fs.readFile() i również nie powinno umieszczać funkcji asynchronicznej wewnątrz try / catch w node.js. metoda try / catch nigdy nie otrzyma błędu, ponieważ jest asynchroniczna. zamiast tego przekaż błąd w wywołaniu zwrotnym i obsłuż go tam: fs.readFile('/etc/passwd', (err, data) => { if (err) throw err; console.log(data); }); from: nodejs.org/dist/latest-v12.x/docs/api/…
KH B
Wierzę, że próba zostanie wywołana, jeśli obietnica zostanie odrzucona, a ty czekasz na obietnicę.
sdgfsdh
0

Spróbuj zamiast tego użyć Async, aby uniknąć blokowania jedynego wątku, który masz w NodeJS. Sprawdź ten przykład:

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

Później można użyć tej funkcji asynchronicznej z try / catch z dowolnej innej funkcji:

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
  }
}

Miłego kodowania!

jdnichollsc
źródło
0

Mechanizmu JavaScript try… catch nie można używać do przechwytywania błędów generowanych przez asynchroniczne interfejsy API. Częstym błędem dla początkujących jest próba użycia metody throw wewnątrz wywołania zwrotnego w pierwszej kolejności błędu:

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

To nie zadziała, ponieważ funkcja wywołania zwrotnego przekazana do fs.readFile () jest wywoływana asynchronicznie. Zanim wywołanie zwrotne zostanie wywołane, otaczający kod, w tym blok try… catch, będzie już zakończony. W większości przypadków zgłoszenie błędu w wywołaniu zwrotnym może spowodować zawieszenie procesu Node.js. Jeśli domeny są włączone lub program obsługi został zarejestrowany w process.on („uncaughtException”), takie błędy mogą zostać przechwycone.

źródło: https://nodejs.org/api/errors.html

ViktorKrpn
źródło