savfilewriter
v1.0.0
Published
A pure JavaScript library for writing SPSS .sav (system) files in the browser or Node.js
Downloads
592
Maintainers
Readme
savwriter
A pure JavaScript library for writing SPSS .sav (system) files in the browser or Node.js.
Overview
savwriter creates uncompressed SPSS .sav files from metadata and data records. It's designed to work seamlessly with data parsed by sav-reader or similar libraries, enabling full round-trip support for SPSS data files.
Features
✅ Write valid .sav files compatible with SPSS Statistics and PSPP ✅ Numeric variables with custom formats (F8.2, COMMA10.2, etc.) ✅ String variables up to 255 bytes (short strings) ✅ Value labels for categorical data ✅ Variable labels with UTF-8 support ✅ Long variable names (>8 characters) ✅ Missing values (SYSMIS for numeric, empty for string) ✅ Uncompressed format (compression=0) ✅ Browser downloads via built-in download() method ✅ Pure JavaScript - no dependencies, works in browsers and Node.js
Installation
// ES6 import
import { SavWriter } from './savwriter/index.js';Quick Start
// Define your data structure
const metadata = {
encoding: 'UTF-8',
fileLabel: 'My Survey Data',
sysvars: [
{
name: 'id',
type: 0, // 0 = numeric
label: 'Respondent ID'
},
{
name: 'age',
type: 0,
label: 'Age in years',
printFormat: 'F3.0'
},
{
name: 'gender',
type: 0,
label: 'Gender',
values: {
'1': 'Male',
'2': 'Female',
'3': 'Other'
}
},
{
name: 'name',
type: 50, // String width in bytes
label: 'Full Name'
}
]
};
// Your data records
const records = [
{ id: 1, age: 28, gender: 1, name: 'John Smith' },
{ id: 2, age: 35, gender: 2, name: 'Jane Doe' },
{ id: 3, age: 42, gender: 1, name: 'Bob Johnson' }
];
// Write to ArrayBuffer
const buffer = SavWriter.write(metadata, records);
// Or download directly in browser
SavWriter.download(metadata, records, 'output.sav');API Reference
SavWriter.write(metadata, records, options)
Writes a complete .sav file to an ArrayBuffer.
Parameters:
metadata(Object): File and variable metadataencoding(String): Character encoding (default: 'UTF-8')fileLabel(String): Optional file descriptionsysvars(Array): Variable definitions
records(Array): Data records as objects with variable names as keysoptions(Object): Optional settingsproduct(String): Product identification stringcompression(Number): Compression type (0 = none, default)
Returns: ArrayBuffer - Binary .sav file data
Example:
const buffer = SavWriter.write(metadata, records, {
fileLabel: 'Custom Dataset'
});SavWriter.download(metadata, records, filename, options)
Writes and downloads a .sav file in the browser.
Parameters:
metadata(Object): File and variable metadatarecords(Array): Data recordsfilename(String): Download filenameoptions(Object): Optional settings (same as write())
Example:
SavWriter.download(metadata, records, 'survey-results.sav');Variable Definition
Each variable in metadata.sysvars should have:
{
name: 'variable_name', // Required: Variable name (any length)
type: 0, // Required: 0=numeric, or string width
label: 'Description', // Optional: Descriptive label
printFormat: 'F8.2', // Optional: Display format
writeFormat: 'F8.2', // Optional: Write format
values: { // Optional: Value labels
'1': 'Label 1',
'2': 'Label 2'
}
}Variable Types
Numeric:
type: 0- Stored as 64-bit float (IEEE 754)
- Missing values represented as SYSMIS (-DBL_MAX)
String:
type: Nwhere N is the width in bytes- Maximum width: 255 bytes (short strings)
- Padded with spaces if value is shorter than width
- Empty/null values stored as spaces
Format Specifications
Formats can be specified as strings:
'F8.2'- Standard numeric (8 chars wide, 2 decimals)'F10.0'- Integer display'COMMA10.2'- Number with comma separators'DOLLAR12.2'- Dollar amount'DATE11'- Date format'A50'- String (50 characters)
Common format types:
F- Standard numericCOMMA- Number with commasDOLLAR- CurrencyPCT- PercentageDATE- DateTIME- TimeA- String
Data Records
Data records are plain JavaScript objects:
const records = [
{
id: 1,
age: 28,
gender: 1,
name: 'John Smith',
income: 50000.00
},
{
id: 2,
age: 35,
gender: 2,
name: 'Jane Doe',
income: 65000.00
}
];Missing Values:
- Numeric: Use
null,undefined, empty string, orNaN - String: Use
null,undefined, or empty string
Complete Example
import { SavWriter } from './savwriter/index.js';
// Survey data with mixed types
const metadata = {
encoding: 'UTF-8',
fileLabel: 'Customer Satisfaction Survey 2025',
sysvars: [
{
name: 'respondent_id',
type: 0,
label: 'Respondent ID',
printFormat: 'F8.0'
},
{
name: 'age',
type: 0,
label: 'Age in years',
printFormat: 'F3.0'
},
{
name: 'satisfaction',
type: 0,
label: 'Overall Satisfaction',
values: {
'1': 'Very Dissatisfied',
'2': 'Dissatisfied',
'3': 'Neutral',
'4': 'Satisfied',
'5': 'Very Satisfied'
}
},
{
name: 'fullname',
type: 50,
label: 'Full Name'
},
{
name: 'comments',
type: 200,
label: 'Additional Comments'
}
]
};
const records = [
{
respondent_id: 1,
age: 28,
satisfaction: 5,
fullname: 'John Smith',
comments: 'Excellent service!'
},
{
respondent_id: 2,
age: 35,
satisfaction: 4,
fullname: 'Jane Doe',
comments: 'Very happy with the product.'
},
{
respondent_id: 3,
age: null, // Missing value
satisfaction: 3,
fullname: 'Bob Johnson',
comments: ''
}
];
// Create and download
SavWriter.download(metadata, records, 'survey-results.sav');File Structure
The library writes .sav files with the following structure:
File Header Record (176 bytes)
- Magic string ($FL2)
- Product identification
- File metadata (cases, variables, encoding)
Variable Records (Type 2)
- One record per variable
- Continuation records for long strings
Value Label Records (Types 3 & 4)
- Type 3: Value-to-label mappings
- Type 4: Variables using those labels
Extension Records (Type 7)
- Character Encoding (Subtype 20)
- Long Variable Names (Subtype 13)
Dictionary Termination (rec_type = 999)
Data Records
- Uncompressed binary data
- One record per case
Testing
Open the example file in a browser to see a comprehensive demonstration:
example_complex_dataset.html- End-to-end integration test with complex data
Additional unit tests are available in the test_files/ directory:
test_files/test-binarywriter.html- Low-level binary writing teststest_files/test-headerwriter.html- File header teststest_files/test-variablewriter.html- Variable record teststest_files/test-valuelabelwriter.html- Value label tests
The complex example includes a "Download Sample File" button to generate a test .sav file.
Limitations (MVP)
- ✅ Uncompressed files only (compression=0)
- ✅ Short strings only (≤255 bytes)
- ❌ No compression support (bytecode or ZLIB)
- ❌ No very long strings (>255 bytes)
- ❌ No missing value specifications (beyond SYSMIS)
- ❌ No document records
- ❌ Limited extension records
Compatibility
- SPSS Statistics (all versions) - ✅ Tested
- PSPP - ✅ Compatible
- R (haven package) - ✅ Compatible
- Python (pyreadstat) - ✅ Compatible
Technical Details
- Endianness: Little-endian (layout_code = 2)
- Encoding: UTF-8 by default
- Missing numeric: -DBL_MAX (-1.7976931348623157e+308)
- String padding: Spaces (0x20)
- Alignment: Variable labels padded to 4-byte boundary, value labels to 8-byte
Use Cases
- Export filtered/modified datasets from SavQuick
- Generate .sav files from survey responses
- Convert CSV/JSON to SPSS format
- Create synthetic test datasets
- Round-trip SPSS data (read with sav-reader, write with savwriter)
Architecture
savwriter/
├── index.js # Public API
├── BinaryWriter.js # Low-level binary writing
├── SavWriter.js # High-level orchestration
├── writers/
│ ├── HeaderWriter.js # File header (176 bytes)
│ ├── VariableWriter.js # Variable metadata
│ ├── ValueLabelWriter.js # Value labels (Types 3 & 4)
│ ├── ExtensionWriter.js # Extension records (Type 7)
│ └── DataWriter.js # Data records
└── utils/
└── FormatEncoder.js # Print/write format encodingContributing
This library was created as part of SavQuick project. Future enhancements:
- Compression support (bytecode, ZLIB)
- Very long strings (>255 bytes)
- Missing value specifications
- Document records
- Additional extension records
References
- PSPP System File Format Specification
- SPSS Statistics File Format Documentation
- IEEE 754 Floating Point Standard
License
Part of the SavQuick project.
Version
1.0.0 - Initial release with uncompressed file support
