Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Well, the obvious way to do that is with \ifeof, but for some reason, I cannot do this right. I wrote

\newread\reader
\openin\reader=empty \relax
\ifeof\reader\message{empty}\else\message{not empty}\fi
\closein\reader
\openin\reader=notempty \relax
\ifeof\reader\message{empty}\else\message{not empty}\fi
\closein\reader

where empty is an empty file (sized 0), and notempty is non-empty file. TeX seems to think that both files are not empty.

share|improve this question

2 Answers 2

up vote 7 down vote accepted

You can use \pdffilesize for simple existence/empty tests:

\def\firstoftwo#1#2{#1}
\def\secondoftwo#1#2{#2}
\def\iffileexist#1{%
  \expandafter\ifx\expandafter&\pdffilesize{#1}&%
    \expandafter\secondoftwo
  \else
    \expandafter\firstoftwo
  \fi
}
\def\iffileempty#1{%
  \ifnum0\pdffilesize{#1}>0
    \expandafter\secondoftwo
  \else
    \expandafter\firstoftwo
  \fi
}
\def\test#1{%
  \iffileexist{#1}{File #1 exists}{File #1 doesn't exist}
  \iffileempty{#1}{File #1 is empty}{File #1 isn't empty}\par
}
\test{notexist}
\test{empty}
\test{nonempty}
\bye

For greater portability you should prefer the pdftexcmds package which makes \pdf@filesize available for both pdfTeX and LuaTeX.

share|improve this answer
    
@Phillip: I think this carves around TeX annoyance in an elegant way. –  Yossi Gil Feb 28 '11 at 7:46

Straight after opening a file \ifeof is false only when the file doesn't exist. You have not tried to read anything yet, so officially the end-of-file marker has not been found yet, even in the case where the file is empty. So you should try to read something from the file into a macro and then check both \ifeof and the macro you read into.

\newread\reader

\def\eolmarker{\par}

\def\testifempty#1{%
\openin\reader=#1\relax
\ifeof\reader
    \message{^^J#1: doesn't exist^^J}%
\else
    \read\reader to \readmacro
    \ifeof\reader
        \ifx\readmacro\eolmarker
            \message{^^J#1: is empty^^J}%
        \else
            \message{^^J#1: is not empty^^J}%
        \fi
    \else
        \message{^^J#1: is not empty^^J}%
    \fi
\fi
\closein\reader
}

\testifempty{empty}%   File "empty" is empty
\testifempty{notempty}% File "notempty" is not empty 
\testifempty{doesnotexist}% File "doesnotexist" doesn't exist

\bye

Run using:

rm -f empty doesnotexist
touch empty
echo "not empty" > notempty
pdflatex <abovecode>.tex

Result:

This is pdfTeX, Version 3.1415926-1.40.11 (TeX Live 2010)
 restricted \write18 enabled.
entering extended mode
(./f.tex 
empty: is empty

notempty: is not empty


doesnotexist: doesn't exists
 )
No pages of output.
Transcript written on f.log.
share|improve this answer
    
Thanks. It works. Take note that it also works if the non-empty file does not contain an eoln, i.e., if you produced with with echo -a " " > notempty. –  Yossi Gil Feb 27 '11 at 20:49
    
I must confess I think this behavior of TeX is a bit "clever" not say "ubersmart". –  Yossi Gil Feb 27 '11 at 20:52
    
How can I make this work for files in which braces are not balanced? –  Hernan Nov 16 '13 at 14:04
1  
@Hernan: Then you need to disable the normal meaning of braces before reading from the file. You then need to wrap the code into a group (\begingroup, \endgroup) so that the change is not global. The code would be like \begingroup\let\do\@makeother\dospecials \read\reader to \readmacro \ifeof\reader\endgroup <then code> \else\endgroup <else code>\fi. You need to place \makeatletter before and \makeatother behind the macro definition then to allow macros with an @ symbol in them. See e.g. tex.stackexchange.com/a/38910/2975 for a similar example. –  Martin Scharrer Nov 17 '13 at 16:25

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.