TL;DR: With find-file-noselect
you have no control about what actually happens, and you may end up with arbitrary minor modes enabling in the buffer, depending on what the user enabled in their init.el
. Also, cleanup is hard.
Use with-temp-buffer
and insert-file-contents
instead. If you need specific major or minor modes in the buffer, enable them explicitly. To write files, use with-temp-file
instead, which—despite its name—lets you write to arbitrary files.
Side effects
find-file-noselect
has a lot of side-effects, including
- interactively asking questions (that alone is a no-go in non-interactive use),
- automatically enabling view mode for readonly files,
- entering normal mode otherwise,
- and running
find-file-hook
.
Normal Mode itself
- automatically selects a proper major mode for the current buffer,
- runs all corresponding major and minor mode hooks,
- and reads all local variables for the current buffer, i.e. file variables and directory variables, which again may ask interactive questions about unsafe local variables.
Since all hooks are run, you get all minor modes and hook functions the user enabled in their init.el
, which can cause everything, from minor inconveniences (if undesirable minor modes are enabled) to major havoc (if the user added a hook function that expects to be called from an interactive context).
See https://github.com/flycheck/flycheck/issues/366 for an example. The use of find-file-noselect
caused a data file to be syntax-checked by Flycheck, and since it was happening at Emacs shut-down, there was no time to properly clean up again, leaving a temporary file behind.
Cleanup
With find-file-noselect
you need to be extra careful to kill the buffer again. find-file-noselect
does not do that for you.
You need to remember the buffer at some place, and carefully use unwind-protect
to make sure that the buffer gets killed even in case of non-local exits.
Alternatives
To read files, use with-temp-buffer
and insert-file-contents
, which only does the most basic things, e.g. coding system conversion, but does not ask questions, enable hooks, or setup local variables:
(with-temp-buffer
(insert-file-contents (locate-user-emacs-file "foo.el"))
;; Enter the major mode explicitly
(emacs-lisp-mode)
;; …
)
with-temp-buffer
takes care to properly kill the temporary buffer at the end of its body.
To write files, use with-temp-file
, which creates a temporary buffer and writes the contents to the given file name at the end of its body:
(with-temp-file (locate-user-emacs-file "foo.el")
(prin1 (list 'my 'data) (current-buffer)))