Table of Contents

1. File Operations

PostScript provides comprehensive file I/O capabilities for reading and writing data, managing resources, and creating modular programs. Understanding file operations is essential for advanced PostScript programming.

1.1. Overview

File operations in PostScript include:

  • File access - Opening, reading, and writing files

  • Standard I/O - stdin, stdout, stderr

  • Filters - Data encoding/decoding

  • String operations - String-based I/O

  • Resource loading - External data and code

  • Temporary storage - Working with file buffers

PostScript treats files as streams of bytes that can be read, written, or both.

1.2. File Basics

1.2.1. Opening Files

% file: filename access file
% access: (r)ead, (w)rite, (r+) read/write

% Open for reading
(input.ps) (r) file /inputFile exch def

% Open for writing
(output.dat) (w) file /outputFile exch def

% Open for read/write
(data.tmp) (r+) file /dataFile exch def

1.2.2. Closing Files

% closefile: file closefile

inputFile closefile
outputFile closefile
dataFile closefile

1.2.3. File Status

% status: file status -> boolean

inputFile status {
  (File is open) print
} {
  (File is closed) print
} ifelse

1.3. Reading from Files

1.3.1. Reading Strings

% read: file read -> int true | false
% Reads one byte

(input.txt) (r) file /f exch def
f read {
  =  % Print the byte
} {
  (End of file) print
} ifelse
f closefile

1.3.2. Reading Lines

% readline: file string readline -> substring true | false

(input.txt) (r) file /f exch def
256 string /buffer exch def

% Read one line
f buffer readline {
  % Got a line
  print
} {
  (End of file) print
} ifelse

f closefile

Reading all lines:

/readAllLines {  % filename -> -
  (r) file
  256 string

  {
    2 copy readline not { exit } if
    print (\n) print
  } loop

  pop closefile
} def

% Usage
(myfile.txt) readAllLines

1.3.3. Reading Tokens

% token: string token -> post any true | false
% token: file token -> any true | false

(data.ps) (r) file /f exch def

% Read PostScript tokens
f token {
  % Got token
  =  % Print it

  % Read another
  f token {
    =
  } if
} if

f closefile

1.3.4. Reading Binary Data

% readstring: file string readstring -> substring boolean

(binary.dat) (r) file /f exch def
1024 string /buffer exch def

f buffer readstring {
  % Read full buffer
  (Read ) print dup length =
} {
  % Read partial (EOF)
  (Read ) print dup length = (bytes before EOF) print
} ifelse

f closefile

1.4. Writing to Files

1.4.1. Writing Strings

% write: file int write

(output.txt) (w) file /f exch def

% Write bytes
f 72 write  % 'H'
f 105 write % 'i'
f 10 write  % newline

f closefile

1.4.2. Writing Lines

% writestring: file string writestring

(output.txt) (w) file /f exch def

f (Hello, World!) writestring
f (\n) writestring
f (Second line) writestring
f (\n) writestring

f closefile

1.4.3. Writing Formatted Data

/writeFormatted {  % file values... count template -> -
  3 dict begin
    /template exch def
    /count exch def
    /f exch def

    % Write formatted output
    count {
      template
      exch =string cvs
      concatstrings
      f exch writestring
    } repeat
  end
} def

% Usage
(output.txt) (w) file /f exch def
f 42 99 2 (Value: %\n) writeFormatted
f closefile
/printToFile {  % filename string -> -
  2 dict begin
    /str exch def
    /fname exch def

    fname (w) file
    dup str writestring
    closefile
  end
} def

% Usage
(output.txt) (Hello from PostScript!) printToFile

1.5. Standard I/O

1.5.1. Standard Input

% Read from stdin
(%stdin) (r) file /stdin exch def

stdin 256 string readline {
  (You entered: ) print
  print
} if

stdin closefile

1.5.2. Standard Output

% Write to stdout
(%stdout) (w) file /stdout exch def

stdout (Output to stdout\n) writestring
stdout closefile

% Or use print operator (writes to stdout)
(Hello, stdout!) print

1.5.3. Standard Error

% Write to stderr
(%stderr) (w) file /stderr exch def

stderr (Error message\n) writestring
stderr closefile

1.6. File Filters

1.6.1. ASCII85 Encoding

% Encode data to ASCII85
(output.a85) (w) file
/ASCII85Encode filter /encoded exch def

encoded (Raw data to encode) writestring
encoded closefile

% Decode ASCII85
(input.a85) (r) file
/ASCII85Decode filter /decoded exch def

256 string /buffer exch def
decoded buffer readstring pop
decoded closefile

1.6.2. Hexadecimal Encoding

% ASCIIHexEncode filter
(output.hex) (w) file
/ASCIIHexEncode filter /hexFile exch def

hexFile (Data) writestring
hexFile closefile

% ASCIIHexDecode filter
(input.hex) (r) file
/ASCIIHexDecode filter /hexIn exch def

256 string hexIn exch readstring pop
hexIn closefile

1.6.3. Run-Length Encoding

% RunLengthEncode filter
(output.rle) (w) file
/RunLengthEncode filter /rleFile exch def

rleFile (Repeated data...) writestring
rleFile closefile

% RunLengthDecode filter
(input.rle) (r) file
/RunLengthDecode filter /rleIn exch def

1024 string rleIn exch readstring pop
rleIn closefile

1.6.4. LZW Compression

% LZWEncode filter
(output.lzw) (w) file
/LZWEncode filter /lzwFile exch def

lzwFile (Compressed data) writestring
lzwFile closefile

% LZWDecode filter
(input.lzw) (r) file
/LZWDecode filter /lzwIn exch def

2048 string lzwIn exch readstring pop
lzwIn closefile

1.7. Temporary Files

1.7.1. Creating Temp Files

/createTempFile {  % -> file
  % Generate temp filename
  /tempName
    (%temp_)
    rand =string cvs
    (.dat)
    3 string copy
    concatstrings exch concatstrings
  def

  tempName (w+) file
} def

% Usage
createTempFile /temp exch def
temp (Temporary data) writestring
temp closefile

1.7.2. String Streams

% Use string as file-like object
/data 1024 string def

% Write to string
data 0 (Hello) putinterval

% Read from string
data 0 5 getinterval
% Returns: (Hello)

1.8. File Positioning

1.8.1. File Position

% fileposition: file -> position

(data.txt) (r) file /f exch def

% Get current position
f fileposition =  % Prints current offset

% Read some data
f 256 string readline pop

% Check new position
f fileposition =

f closefile

1.8.2. Setting Position

% setfileposition: file position setfileposition

(data.txt) (r+) file /f exch def

% Seek to position 100
f 100 setfileposition

% Read from that position
f 256 string readline pop

f closefile

1.8.3. Rewinding Files

/rewindFile {  % file -> -
  0 setfileposition
} def

% Usage
f rewindFile

1.9. Loading External Code

1.9.1. Running External Scripts

% run: filename run
% Executes PostScript file

(library.ps) run

% Or with error handling
(script.ps) {
  run
} stopped {
  (Error loading script) print
} if

1.9.2. Including Libraries

/includeLibrary {  % filename -> -
  dup
  {
    run
  } stopped {
    pop
    ( not found) exch concatstrings print
  } {
    pop
  } ifelse
} def

% Usage
(utils.ps) includeLibrary
(graphics.ps) includeLibrary

1.9.3. Resource Files

/loadResource {  % resourceName -> -
  1 dict begin
    /name exch def

    % Try different locations
    [
      (resources/) name concatstrings
      (lib/) name concatstrings
      name
    ] {
      dup status {
        run
        exit
      } {
        pop
      } ifelse
    } forall
  end
} def

% Usage
(colors.ps) loadResource

1.10. Data Files

1.10.1. CSV File Reading

/readCSV {  % filename -> array
  10 dict begin
    /lines [] def

    (r) file
    256 string

    {
      2 copy readline not { exit } if

      % Parse CSV line
      (,) {
        search {
          % Found comma
          /lines [ lines aload pop 4 -1 roll ] def
        } {
          % Last field
          /lines [ lines aload pop ] def
          exit
        } ifelse
      } loop
    } loop

    pop closefile
    lines
  end
} def

% Usage
(data.csv) readCSV

1.10.2. Configuration Files

/loadConfig {  % filename -> dict
  10 dict begin
    /config 20 dict def

    (r) file /f exch def
    256 string /line exch def

    {
      f line readline not { exit } if

      % Parse key=value
      (=) search {
        % Found =
        /value exch def
        pop  % Discard =
        /key exch def

        % Store in config
        config key value put
      } {
        % No =, skip line
        pop
      } ifelse
    } loop

    f closefile
    config
  end
} def

% Usage
(config.txt) loadConfig /settings exch def
settings /server get print

1.10.3. JSON-like Data

/parseSimpleJSON {  % string -> dict
  % Simplified JSON parser
  % Format: {key: value, key: value}

  20 dict begin
    /result 10 dict def

    % Remove braces
    dup 0 get 123 eq { 1 exch length 2 sub getinterval } if

    % Split by comma
    {
      (,) search {
        % Parse key:value pair
        (:) search {
          /value exch def
          pop
          /key exch def

          % Clean and store
          result
          key strip
          value strip
          put
        } if
      } {
        % Last pair
        (:) search {
          /value exch def
          pop
          /key exch def
          result key strip value strip put
        } if
        exit
      } ifelse
    } loop

    result
  end
} def

/strip {  % string -> trimmedString
  % Remove leading/trailing spaces
  dup length 0 gt {
    dup 0 get 32 eq {
      1 exch length 1 sub getinterval strip
    } if
  } if
} def

1.11. File Management

1.11.1. File Existence Check

/fileExists {  % filename -> boolean
  {
    (r) file closefile
    true
  } stopped {
    pop false
  } ifelse
} def

% Usage
(myfile.txt) fileExists {
  (File exists) print
} {
  (File not found) print
} ifelse

1.11.2. File Copy

/copyFile {  % srcFile dstFile -> -
  2 dict begin
    /dst exch def
    /src exch def

    src (r) file /inFile exch def
    dst (w) file /outFile exch def

    1024 string /buffer exch def

    {
      inFile buffer readstring {
        outFile exch writestring
      } {
        outFile exch writestring
        exit
      } ifelse
    } loop

    inFile closefile
    outFile closefile
  end
} def

% Usage
(source.txt) (destination.txt) copyFile

1.11.3. File Append

/appendToFile {  % filename string -> -
  2 dict begin
    /str exch def
    /fname exch def

    fname (a) file
    dup str writestring
    closefile
  end
} def

% Usage
(log.txt) (New log entry\n) appendToFile

1.12. Binary File Operations

1.12.1. Writing Binary Data

/writeBinary {  % filename data -> -
  2 dict begin
    /data exch def
    /fname exch def

    fname (w) file /f exch def

    data {
      f exch write
    } forall

    f closefile
  end
} def

% Usage
(binary.dat) [0 255 128 64 32] writeBinary

1.12.2. Reading Binary Data

/readBinary {  % filename size -> array
  2 dict begin
    /size exch def
    /fname exch def

    fname (r) file /f exch def
    size string /buffer exch def

    f buffer readstring pop
    f closefile

    [
      0 1 buffer length 1 sub {
        buffer exch get
      } for
    ]
  end
} def

% Usage
(binary.dat) 100 readBinary

1.13. Practical Examples

1.13.1. Example 1: Log File Writer

/Logger {
  10 dict begin
    /logFile null def
    /filename exch def

    /open {
      filename (a) file /logFile exch def
    } def

    /close {
      logFile null ne {
        logFile closefile
        /logFile null def
      } if
    } def

    /log {  % message level -> -
      2 dict begin
        /level exch def
        /msg exch def

        logFile null eq { open } if

        % Format: [timestamp] LEVEL: message
        logFile ([) writestring
        logFile realtime =string cvs writestring
        logFile (] ) writestring
        logFile level writestring
        logFile (: ) writestring
        logFile msg writestring
        logFile (\n) writestring
      end
    } def

    currentdict
  end
} def

% Usage
(app.log) Logger /logger exch def
logger /log (Application started) (INFO) exec
logger /log (Processing data) (DEBUG) exec
logger /log (Error occurred) (ERROR) exec
logger /close exec

1.13.2. Example 2: Data Exporter

/DataExporter {
  10 dict begin
    /data exch def
    /filename exch def

    /exportCSV {
      filename (w) file /f exch def

      % Write header
      f (X,Y,Value\n) writestring

      % Write data
      data {
        aload pop
        f exch =string cvs writestring
        f (,) writestring
        f exch =string cvs writestring
        f (,) writestring
        f exch =string cvs writestring
        f (\n) writestring
      } forall

      f closefile
    } def

    currentdict
  end
} def

% Usage
[
  [10 20 100]
  [30 40 200]
  [50 60 300]
] (data.csv) DataExporter /exporter exch def
exporter /exportCSV exec

1.13.3. Example 3: Template Processor

{% raw %}
/processTemplate {  % templateFile dataDict outputFile -> -
  3 dict begin
    /outFile exch def
    /data exch def
    /tmplFile exch def

    tmplFile (r) file /inF exch def
    outFile (w) file /outF exch def
    256 string /line exch def

    {
      inF line readline not { exit } if

      % Replace {{key}} with value
      {
        ({{) search not { exit } if

        % Write before match
        outF exch writestring
        pop  % Discard {{

        (}}) search {
          % Found closing }}
          /key exch def
          pop  % Discard }}

          % Write replacement
          data key known {
            outF data key get writestring
          } {
            outF ({{) writestring
            outF key writestring
            outF (}}) writestring
          } ifelse
        } {
          % No closing }}
          outF ({{) writestring
        } ifelse
      } loop

      % Write rest of line
      outF exch writestring
      outF (\n) writestring
    } loop

    inF closefile
    outF closefile
  end
} def

% Usage
<<
  /name (John Doe)
  /email (john@example.com)
>> (template.txt) (output.txt) processTemplate
{% endraw %}

1.13.4. Example 4: Batch File Processor

/processBatch {  % directory pattern processor -> -
  3 dict begin
    /proc exch def
    /pattern exch def
    /dir exch def

    % List files matching pattern
    % (simplified - actual file listing is system-dependent)
    [
      (file1.txt)
      (file2.txt)
      (file3.txt)
    ] {
      /filename exch def

      % Process each file
      dir filename concatstrings proc exec
    } forall
  end
} def

% Usage
(data/) (*.txt) {
  dup print ( processed) print (\n) print
  % Process file here
} processBatch

1.14. Error Handling

1.14.1. Safe File Operations

/safeFileOpen {  % filename mode -> file true | false
  2 copy
  {
    file
    true
  } stopped {
    pop pop pop
    false
  } ifelse
} def

% Usage
(myfile.txt) (r) safeFileOpen {
  /f exch def
  % Use file
  f closefile
} {
  (Could not open file) print
} ifelse

1.14.2. File Operation with Cleanup

/withFile {  % filename mode proc -> -
  3 dict begin
    /proc exch def
    /mode exch def
    /fname exch def

    fname mode file /f exch def

    {
      f proc exec
    } stopped {
      % Ensure file is closed on error
      f closefile
      (File operation failed) print
    } {
      f closefile
    } ifelse
  end
} def

% Usage
(data.txt) (r) {
  256 string readline {
    print
  } if
} withFile

1.15. Performance Tips

1.15.1. Buffer Size

% Good: appropriate buffer
4096 string /buffer exch def
file buffer readstring

% Bad: tiny buffer (many reads)
10 string /buffer exch def
file buffer readstring

1.15.2. Batch Writes

% Good: batch writes
file (Line 1\n) (Line 2\n) (Line 3\n)
concatstrings exch concatstrings
writestring

% Less efficient: many small writes
file (Line 1\n) writestring
file (Line 2\n) writestring
file (Line 3\n) writestring

1.15.3. Close Files Promptly

% Good: close when done
file dup ... closefile

% Bad: keep open unnecessarily
file /f exch def
% ... long time
f closefile

1.16. Best Practices

1.16.1. Always Close Files

% Good: guaranteed close
(file.txt) (r) file
dup
% ... use file
closefile

% Better: with error handling
{
  (file.txt) (r) file
  dup
  % ... use file
  closefile
} stopped {
  pop
  (Error) print
} if

1.16.2. Check File Operations

% Good: check results
file string readline {
  % Success
} {
  % EOF or error
} ifelse

% Bad: assume success
file string readline pop
% May fail silently

1.16.3. Use Appropriate Access Modes

% Good: correct mode
(input.txt) (r) file   % Read-only
(output.txt) (w) file  % Write-only
(data.txt) (r+) file   % Read-write

% Bad: wrong mode
(input.txt) (w) file   % Truncates!
(output.txt) (r) file  % Can't write

1.17. Common Pitfalls

1.17.1. Not Closing Files

% Wrong: file leak
(file.txt) (r) file
% ... forget to close

% Correct
(file.txt) (r) file
dup
% ... use file
closefile

1.17.2. Wrong String Size

% Wrong: buffer too small
file 10 string readline  % May truncate

% Correct: adequate buffer
file 256 string readline

1.17.3. Forgetting EOF Check

% Wrong: assumes data available
file string readline pop
% May fail at EOF

% Correct: check EOF
file string readline {
  % Got data
} {
  % EOF
} ifelse

1.18. See Also


Back to top

Copyright © 2025 Ribose. PostScript is a trademark of Adobe. Distributed under the MIT License.