tex中的文件输出
tex中的文件输出
总所周知,任何编程系统都离不开输入输出的。在latex中我们很熟悉文件输入的方式,比如input,include。但对于文件输出的方式并不是非常熟悉,但实际上应用非常多的,比如编译时输出的辅助文件。下面我们来看一看,tex系统中的文件输出方式,以及在filecontents宏包,参考文献相关命令bibliography带来的输出,以及biblatex宏包中的输出。
1. tex系统文件输出方式
tex系统中的文件输出方式,与常见编程语言的文件输出是类似的。先打开一个文件,赋予一个句柄(或通道),然后顺着该句柄输出需要输出的内容,然后关闭文件。
打开和关闭文件的命令为openout,closeout,写一行内容的命令为write,下面为一个简单的例子:
% !Mode:: "TeX:UTF-8"
\documentclass{article}
\usepackage{ctex}
\begin{document}
\newwrite\foutfile
\immediate\openout\foutfile\jobname.dat
\def\outcmd{}
\immediate\write\foutfile{\string\outcmd}
\immediate\write\foutfile{A string to out}
\newcounter{numberA}
\setcounter{numberA}{0}
\loop \stepcounter{numberA} \ifnum\thenumberA<10 \immediate\write\foutfile{\thenumberA} \repeat
\immediate\closeout\foutfile
\end{document}
其中:输出的文件当前tex文件名.dat,第一个write输出了一个转换为文本的记号,第二个write输出了一个简单的字符串,第三个write则循环输出了1到9共9个数字。immediate命令表示立即执行输出。
输出的文件内容为:
\outcmd
A string to out
1
2
3
4
5
6
7
8
9
2. filecontents宏包的文件输出
其输出函数为filec@ntents,一个参数是文件名,首先检测了一些是否存在当前文件,接着用句柄\reserved@c打开文件,输出文档基本信息,然后利用一个循环把环境内的各行输出到文件中。
\gdef\filec@ntents#1{%
\openin\@inputcheck#1 %
\ifeof\@inputcheck%
\@latex@warning@no@line%
{Writing file `\@currdir#1'}%
\else %
\@latex@warning@no@line%
{Overwriting file `\@currdir#1'}%
\fi %
\closein\@inputcheck %
\chardef\reserved@c15 %
\ch@ck7\reserved@c\write%
\immediate\openout\reserved@c#1\relax%
\if@tempswa%
\immediate\write\reserved@c{%
\@percentchar\@percentchar\space%
\expandafter\@gobble\string\LaTeX2e file `#1'^^J%
\@percentchar\@percentchar\space generated by the %
`\@currenvir' \expandafter\@gobblefour\string\newenvironment^^J%
\@percentchar\@percentchar\space from source `\jobname' on %
\number\year/\two@digits\month/\two@digits\day.^^J%
\@percentchar\@percentchar}%
\fi%
\let\do\@makeother\dospecials%
\count0=128\relax %
\loop %
\catcode\count0=11\relax %
\advance\count0 by 1\relax %
\ifnum\count0<256 %
\repeat %
\edef\E{\@backslashchar end\string{\@currenvir\string}}%
\edef\reserved@b{%
\def\noexpand\reserved@b%
####1\E####2\E####3\relax}%
\reserved@b{%
\ifx\relax##3\relax%
\immediate\write\reserved@c{##1}%
\else%
\edef^^M{\noexpand\end{\@currenvir}}%
\ifx\relax##1\relax%
\else%
\@latex@warning{Writing text `##1' before %
\string\end{\@currenvir}\MessageBreak as last line of #1}%
\immediate\write\reserved@c{##1}%
\fi%
\ifx\relax##2\relax%
\else%
\@latex@warning{%
Ignoring text `##2' after \string\end{\@currenvir}}%
\fi%
\fi%
^^M}%
\catcode`\^^L\active%
\let\L\@undefined%
\def^^L{\@ifundefined L^^J^^J^^J}%
\catcode`\^^I\active%
\let\I\@undefined%
\def^^I{\@ifundefined I\space\space}%
\catcode`\^^M\active%
\edef^^M##1^^M{%
\noexpand\reserved@b##1\E\E\relax}}%
2. latex内核命令\bibliography
的文件输出
详见source2e.PDF,ltbibl.dtx一节。latex中利用命令\bibliography
把参考文献信息写入到辅助文件中,然后由bibtex进行处理。
\def\bibliography#1{%
\if@filesw
\immediate\write\@auxout{\string\bibdata{#1}}%
\fi
\@input@{\jobname.bbl}}
可以看到这是一个很简单的定义,就是把bib文件名输出到\@auxout
句柄定义的辅助文件中,而且就只有一行数据\bibdata{bibfilename}
。这样bibtex通过该行信息,确定文献信息所在的bib文件,进而进一步处理。
3. biblatex宏包的bcf文件输出
可以看到biblatex写bcf文件主控函数是\def\blx@ctrlwrite{
,其中文件打开和关闭为:
\immediate\openout\blx@bcfout\jobname.bcf\relax
\blx@auxwrite\blx@bcfout{}{\blx@tempa}%
\global\undef\blx@tempa
\endgroup
\AfterEndDocument{%
\def\do##1{%
\csxappto{blx@sortingtemplates}{%
\blx@xml@sortingtemplate{##1}
{\ifcsdef{blx@sortdef@locale@##1}{ locale="\csuse{blx@sortdef@locale@##1}"}{}}
{\csuse{blx@sortingtemplate@##1}}}}%
\dolistloop\blx@sortingtemplatenames
\blx@auxwrite\blx@bcfout{}{%
\blx@xml@endsection\blx@nl
\blx@xml@comment{SORTING TEMPLATES}%
\csuse{blx@sortingtemplates}%
\blx@xml@comment{DATALISTS}%
\csuse{blx@dlists}%
\blx@xml@endfile}%
\immediate\closeout\blx@bcfout}}
其中,关闭文件是文件编译结尾处。定义的写文件\blx@auxwrite
函数为:
\protected\def\blx@auxwrite#1#2#3{%
\if@filesw
\begingroup
\blx@safe@actives
\let\protect\string
#2%
\immediate\write#1{#3}%
\endgroup
\fi}
其中#1
为文件句柄,#3
为输出的内容。
4. 小结
可以看到,tex 中输出文件是一件比较常见的事情,而且大有作用,很多情况下用来输出一些辅助信息,帮助额外的程序比如bibtex,biber等进行下一步处理。如果要设计一个宏包,也考虑需要源文档中的信息来进一步额外处理,那么类似的方式是可以采用的。