What Is a .XLS File?

Microsoft Excel CDF document

📂Document
🏷️.xls
🎯application/vnd.ms-excel

XLS (Excel 97-2003 Binary Format)

Overview

Microsoft Excel Binary File Format (XLS) is the legacy spreadsheet format used by Microsoft Excel 97 through Excel 2003. It stores spreadsheet data in a binary format using the Compound Document File (CDF) structure, supporting multiple worksheets, formulas, formatting, and macros.

Technical Specifications

  • Format Type: Binary spreadsheet format
  • File Extension: .xls
  • MIME Type: application/vnd.ms-excel
  • Container: Compound Document Format (CDF/OLE2)
  • Maximum Rows: 65,536 (2^16)
  • Maximum Columns: 256 (IV)
  • Maximum Cells: 16,777,216
  • File Size Limit: ~2GB

Format Structure

XLS files use the Compound Document Format with:

  • Directory structure for organizing streams
  • Workbook stream containing spreadsheet data
  • Record-based binary structure (BIFF format)
  • Formula records with binary encoding
  • Formatting and style information
  • Optional VBA macro storage

History and Development

  • 1987: Excel 2.0 introduced .xls format
  • 1990: Excel 3.0 expanded capabilities
  • 1992: Excel 4.0 added macro support
  • 1995: Excel 95 (version 7.0) significant updates
  • 1997: Excel 97 introduced BIFF8 format
  • 2007: Replaced by XLSX format but maintained compatibility

Use Cases

  • Legacy Excel spreadsheet files
  • Financial models and calculations
  • Data analysis and reporting
  • Business process automation with macros
  • Compatibility with older Excel versions
  • Enterprise systems integration

Code Examples

Python XLS Processing with xlrd/xlwt

import xlrd
import xlwt
from datetime import datetime, date
import os

class XLSProcessor:
    def __init__(self):
        self.workbook = None
    
    def read_xls_file(self, filepath):
        """Read and analyze XLS file."""
        try:
            self.workbook = xlrd.open_workbook(filepath, formatting_info=True)
            
            info = {
                'filename': os.path.basename(filepath),
                'sheets': [],
                'creation_date': None,
                'last_modified': None,
                'has_macros': self.workbook.book_type == xlrd.XL_WORKBOOK_BIFF8,
                'codepage': self.workbook.codepage
            }
            
            # Process each worksheet
            for sheet_idx in range(self.workbook.nsheets):
                sheet = self.workbook.sheet_by_index(sheet_idx)
                sheet_info = self.analyze_sheet(sheet)
                info['sheets'].append(sheet_info)
            
            return info
            
        except Exception as e:
            print(f"Error reading XLS file: {e}")
            return None
    
    def analyze_sheet(self, sheet):
        """Analyze individual worksheet."""
        sheet_info = {
            'name': sheet.name,
            'rows': sheet.nrows,
            'cols': sheet.ncols,
            'cells_with_data': 0,
            'formulas': 0,
            'data_types': {
                'text': 0,
                'number': 0,
                'date': 0,
                'boolean': 0,
                'error': 0,
                'empty': 0
            },
            'sample_data': []
        }
        
        # Analyze cell data
        for row in range(min(sheet.nrows, 1000)):  # Limit analysis for performance
            for col in range(sheet.ncols):
                cell = sheet.cell(row, col)
                
                if cell.ctype != xlrd.XL_CELL_EMPTY:
                    sheet_info['cells_with_data'] += 1
                    
                    # Count data types
                    if cell.ctype == xlrd.XL_CELL_TEXT:
                        sheet_info['data_types']['text'] += 1
                    elif cell.ctype == xlrd.XL_CELL_NUMBER:
                        if xlrd.xldate.xldate_isdate(cell.value, self.workbook.datemode):
                            sheet_info['data_types']['date'] += 1
                        else:
                            sheet_info['data_types']['number'] += 1
                    elif cell.ctype == xlrd.XL_CELL_BOOLEAN:
                        sheet_info['data_types']['boolean'] += 1
                    elif cell.ctype == xlrd.XL_CELL_ERROR:
                        sheet_info['data_types']['error'] += 1
                    
                    # Check for formulas
                    formula = sheet.cell_formula(row, col)
                    if formula:
                        sheet_info['formulas'] += 1
                    
                    # Collect sample data (first 10 rows)
                    if row < 10 and len(sheet_info['sample_data']) < 10:
                        value = self.format_cell_value(cell, self.workbook.datemode)
                        if row == len(sheet_info['sample_data']):
                            sheet_info['sample_data'].append([])
                        sheet_info['sample_data'][row].append(value)
                else:
                    sheet_info['data_types']['empty'] += 1
        
        return sheet_info
    
    def format_cell_value(self, cell, datemode):
        """Format cell value for display."""
        if cell.ctype == xlrd.XL_CELL_EMPTY:
            return ""
        elif cell.ctype == xlrd.XL_CELL_TEXT:
            return cell.value
        elif cell.ctype == xlrd.XL_CELL_NUMBER:
            if xlrd.xldate.xldate_isdate(cell.value, datemode):
                date_tuple = xlrd.xldate.xldate_as_tuple(cell.value, datemode)
                return datetime(*date_tuple).strftime("%Y-%m-%d %H:%M:%S")
            else:
                return cell.value
        elif cell.ctype == xlrd.XL_CELL_BOOLEAN:
            return bool(cell.value)
        elif cell.ctype == xlrd.XL_CELL_ERROR:
            return f"ERROR: {cell.value}"
        else:
            return str(cell.value)
    
    def convert_to_csv(self, xls_path, output_dir=None):
        """Convert XLS sheets to CSV files."""
        if not self.workbook:
            self.workbook = xlrd.open_workbook(xls_path)
        
        if not output_dir:
            output_dir = os.path.dirname(xls_path)
        
        base_name = os.path.splitext(os.path.basename(xls_path))[0]
        csv_files = []
        
        for sheet_idx in range(self.workbook.nsheets):
            sheet = self.workbook.sheet_by_index(sheet_idx)
            
            # Create CSV filename
            sheet_name = sheet.name.replace('/', '_').replace('\\', '_')
            csv_filename = f"{base_name}_{sheet_name}.csv"
            csv_path = os.path.join(output_dir, csv_filename)
            
            # Write CSV
            import csv
            with open(csv_path, 'w', newline='', encoding='utf-8') as csvfile:
                writer = csv.writer(csvfile)
                
                for row in range(sheet.nrows):
                    row_data = []
                    for col in range(sheet.ncols):
                        cell = sheet.cell(row, col)
                        value = self.format_cell_value(cell, self.workbook.datemode)
                        row_data.append(value)
                    writer.writerow(row_data)
            
            csv_files.append(csv_path)
            print(f"Converted sheet '{sheet.name}' to {csv_path}")
        
        return csv_files
    
    def extract_formulas(self, xls_path):
        """Extract all formulas from XLS file."""
        if not self.workbook:
            self.workbook = xlrd.open_workbook(xls_path, formatting_info=True)
        
        formulas = []
        
        for sheet_idx in range(self.workbook.nsheets):
            sheet = self.workbook.sheet_by_index(sheet_idx)
            
            for row in range(sheet.nrows):
                for col in range(sheet.ncols):
                    formula = sheet.cell_formula(row, col)
                    if formula:
                        cell_ref = xlrd.cellname(row, col)
                        formulas.append({
                            'sheet': sheet.name,
                            'cell': cell_ref,
                            'formula': formula,
                            'value': sheet.cell_value(row, col)
                        })
        
        return formulas

# Create XLS files with xlwt
class XLSCreator:
    def __init__(self):
        self.workbook = xlwt.Workbook()
        self.styles = self._create_styles()
    
    def _create_styles(self):
        """Create common cell styles."""
        styles = {}
        
        # Header style
        header_style = xlwt.XFStyle()
        header_font = xlwt.Font()
        header_font.bold = True
        header_font.colour_index = xlwt.Style.colour_map['white']
        header_style.font = header_font
        
        header_pattern = xlwt.Pattern()
        header_pattern.pattern = xlwt.Pattern.SOLID_PATTERN
        header_pattern.pattern_fore_colour = xlwt.Style.colour_map['dark_blue']
        header_style.pattern = header_pattern
        
        styles['header'] = header_style
        
        # Date style
        date_style = xlwt.XFStyle()
        date_style.num_format_str = 'YYYY-MM-DD'
        styles['date'] = date_style
        
        # Currency style
        currency_style = xlwt.XFStyle()
        currency_style.num_format_str = '$#,##0.00'
        styles['currency'] = currency_style
        
        # Percentage style
        percent_style = xlwt.XFStyle()
        percent_style.num_format_str = '0.00%'
        styles['percent'] = percent_style
        
        return styles
    
    def create_sample_spreadsheet(self, filename):
        """Create a sample XLS file with various data types."""
        sheet = self.workbook.add_sheet('Sample Data')
        
        # Headers
        headers = ['ID', 'Name', 'Date', 'Amount', 'Percentage', 'Active']
        for col, header in enumerate(headers):
            sheet.write(0, col, header, self.styles['header'])
        
        # Sample data
        sample_data = [
            [1, 'John Doe', date(2023, 1, 15), 1250.50, 0.125, True],
            [2, 'Jane Smith', date(2023, 2, 20), 2100.75, 0.089, True],
            [3, 'Bob Johnson', date(2023, 3, 10), 875.25, 0.156, False],
            [4, 'Alice Brown', date(2023, 4, 5), 3200.00, 0.234, True],
            [5, 'Charlie Wilson', date(2023, 5, 12), 1890.30, 0.098, True]
        ]
        
        for row, data in enumerate(sample_data, 1):
            sheet.write(row, 0, data[0])  # ID
            sheet.write(row, 1, data[1])  # Name
            sheet.write(row, 2, data[2], self.styles['date'])  # Date
            sheet.write(row, 3, data[3], self.styles['currency'])  # Amount
            sheet.write(row, 4, data[4], self.styles['percent'])  # Percentage
            sheet.write(row, 5, data[5])  # Active
        
        # Add formulas
        formula_sheet = self.workbook.add_sheet('Formulas')
        formula_sheet.write(0, 0, 'Sum:', self.styles['header'])
        formula_sheet.write(0, 1, xlwt.Formula('SUM(A2:A6)'))
        
        formula_sheet.write(1, 0, 'Average:', self.styles['header'])
        formula_sheet.write(1, 1, xlwt.Formula('AVERAGE(A2:A6)'))
        
        formula_sheet.write(2, 0, 'Count:', self.styles['header'])
        formula_sheet.write(2, 1, xlwt.Formula('COUNT(A2:A6)'))
        
        # Save workbook
        self.workbook.save(filename)
        print(f"Sample XLS file created: {filename}")
    
    def create_from_data(self, data, filename, sheet_name='Data'):
        """Create XLS file from Python data."""
        sheet = self.workbook.add_sheet(sheet_name)
        
        if not data:
            return
        
        # Write headers if data is list of dictionaries
        if isinstance(data[0], dict):
            headers = list(data[0].keys())
            for col, header in enumerate(headers):
                sheet.write(0, col, header, self.styles['header'])
            
            # Write data
            for row, record in enumerate(data, 1):
                for col, header in enumerate(headers):
                    value = record.get(header, '')
                    
                    # Apply appropriate style based on data type
                    if isinstance(value, datetime):
                        sheet.write(row, col, value, self.styles['date'])
                    elif isinstance(value, (int, float)) and col in [3, 4]:  # Assuming currency columns
                        sheet.write(row, col, value, self.styles['currency'])
                    else:
                        sheet.write(row, col, value)
        
        # Write data if it's a list of lists
        elif isinstance(data[0], (list, tuple)):
            for row, record in enumerate(data):
                for col, value in enumerate(record):
                    sheet.write(row, col, value)
        
        self.workbook.save(filename)
        print(f"XLS file created from data: {filename}")

# Usage examples
def analyze_xls_file(filepath):
    """Analyze and display XLS file information."""
    processor = XLSProcessor()
    info = processor.read_xls_file(filepath)
    
    if not info:
        return
    
    print(f"File: {info['filename']}")
    print(f"Sheets: {len(info['sheets'])}")
    print(f"Has Macros: {info['has_macros']}")
    print(f"Codepage: {info['codepage']}")
    print("-" * 50)
    
    for sheet in info['sheets']:
        print(f"\nSheet: {sheet['name']}")
        print(f"  Dimensions: {sheet['rows']} rows × {sheet['cols']} columns")
        print(f"  Cells with data: {sheet['cells_with_data']}")
        print(f"  Formulas: {sheet['formulas']}")
        print(f"  Data types: {sheet['data_types']}")
        
        if sheet['sample_data']:
            print(f"  Sample data (first few rows):")
            for i, row in enumerate(sheet['sample_data'][:3]):
                print(f"    Row {i+1}: {row[:5]}...")  # Show first 5 columns

def batch_convert_xls_to_csv(directory):
    """Convert all XLS files in directory to CSV."""
    processor = XLSProcessor()
    
    for filename in os.listdir(directory):
        if filename.lower().endswith('.xls'):
            filepath = os.path.join(directory, filename)
            print(f"\nProcessing: {filename}")
            
            try:
                csv_files = processor.convert_to_csv(filepath)
                print(f"Created {len(csv_files)} CSV files")
            except Exception as e:
                print(f"Error converting {filename}: {e}")

# Example usage
if __name__ == "__main__":
    # Create sample XLS file
    creator = XLSCreator()
    creator.create_sample_spreadsheet('sample.xls')
    
    # Analyze the created file
    analyze_xls_file('sample.xls')
    
    # Convert to CSV
    processor = XLSProcessor()
    processor.convert_to_csv('sample.xls')
    
    # Extract formulas
    formulas = processor.extract_formulas('sample.xls')
    if formulas:
        print("\nFormulas found:")
        for formula in formulas:
            print(f"  {formula['sheet']}!{formula['cell']}: {formula['formula']}")

Java XLS Processing with Apache POI

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellReference;

import java.io.*;
import java.util.*;

public class XLSProcessor {
    
    public static class XLSInfo {
        public String filename;
        public int numberOfSheets;
        public List<SheetInfo> sheets = new ArrayList<>();
        public boolean hasMacros;
        
        public static class SheetInfo {
            public String name;
            public int rows;
            public int columns;
            public int cellsWithData;
            public int formulas;
            public Map<String, Integer> dataTypes = new HashMap<>();
        }
    }
    
    public static XLSInfo analyzeXLSFile(String filepath) throws IOException {
        XLSInfo info = new XLSInfo();
        info.filename = new File(filepath).getName();
        
        try (FileInputStream fis = new FileInputStream(filepath);
             HSSFWorkbook workbook = new HSSFWorkbook(fis)) {
            
            info.numberOfSheets = workbook.getNumberOfSheets();
            info.hasMacros = workbook.containsMacros();
            
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                HSSFSheet sheet = workbook.getSheetAt(i);
                XLSInfo.SheetInfo sheetInfo = analyzeSheet(sheet);
                info.sheets.add(sheetInfo);
            }
        }
        
        return info;
    }
    
    private static XLSInfo.SheetInfo analyzeSheet(HSSFSheet sheet) {
        XLSInfo.SheetInfo sheetInfo = new XLSInfo.SheetInfo();
        sheetInfo.name = sheet.getSheetName();
        sheetInfo.rows = sheet.getLastRowNum() + 1;
        
        // Initialize data type counters
        sheetInfo.dataTypes.put("STRING", 0);
        sheetInfo.dataTypes.put("NUMERIC", 0);
        sheetInfo.dataTypes.put("BOOLEAN", 0);
        sheetInfo.dataTypes.put("FORMULA", 0);
        sheetInfo.dataTypes.put("ERROR", 0);
        sheetInfo.dataTypes.put("BLANK", 0);
        
        int maxColumns = 0;
        
        for (Row row : sheet) {
            maxColumns = Math.max(maxColumns, row.getLastCellNum());
            
            for (Cell cell : row) {
                if (cell.getCellType() != CellType.BLANK) {
                    sheetInfo.cellsWithData++;
                }
                
                // Count cell types
                switch (cell.getCellType()) {
                    case STRING:
                        sheetInfo.dataTypes.merge("STRING", 1, Integer::sum);
                        break;
                    case NUMERIC:
                        sheetInfo.dataTypes.merge("NUMERIC", 1, Integer::sum);
                        break;
                    case BOOLEAN:
                        sheetInfo.dataTypes.merge("BOOLEAN", 1, Integer::sum);
                        break;
                    case FORMULA:
                        sheetInfo.dataTypes.merge("FORMULA", 1, Integer::sum);
                        sheetInfo.formulas++;
                        break;
                    case ERROR:
                        sheetInfo.dataTypes.merge("ERROR", 1, Integer::sum);
                        break;
                    case BLANK:
                        sheetInfo.dataTypes.merge("BLANK", 1, Integer::sum);
                        break;
                }
            }
        }
        
        sheetInfo.columns = maxColumns;
        return sheetInfo;
    }
    
    public static void convertXLSToCSV(String xlsPath, String outputDir) throws IOException {
        try (FileInputStream fis = new FileInputStream(xlsPath);
             HSSFWorkbook workbook = new HSSFWorkbook(fis)) {
            
            String baseName = new File(xlsPath).getName().replaceFirst("[.][^.]+$", "");
            
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                HSSFSheet sheet = workbook.getSheetAt(i);
                String csvFileName = baseName + "_" + sheet.getSheetName() + ".csv";
                String csvPath = new File(outputDir, csvFileName).getPath();
                
                try (PrintWriter pw = new PrintWriter(new FileWriter(csvPath))) {
                    for (Row row : sheet) {
                        List<String> values = new ArrayList<>();
                        
                        for (int j = 0; j < row.getLastCellNum(); j++) {
                            Cell cell = row.getCell(j);
                            String value = getCellValueAsString(cell);
                            values.add(escapeCsvValue(value));
                        }
                        
                        pw.println(String.join(",", values));
                    }
                }
                
                System.out.println("Converted sheet '" + sheet.getSheetName() + 
                                 "' to " + csvPath);
            }
        }
    }
    
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }
        
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                try {
                    return String.valueOf(cell.getNumericCellValue());
                } catch (IllegalStateException e) {
                    return cell.getStringCellValue();
                }
            case ERROR:
                return "ERROR:" + cell.getErrorCellValue();
            case BLANK:
            default:
                return "";
        }
    }
    
    private static String escapeCsvValue(String value) {
        if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
            return "\"" + value.replace("\"", "\"\"") + "\"";
        }
        return value;
    }
    
    public static void createSampleXLS(String filename) throws IOException {
        try (HSSFWorkbook workbook = new HSSFWorkbook()) {
            HSSFSheet sheet = workbook.createSheet("Sample Data");
            
            // Create header style
            HSSFCellStyle headerStyle = workbook.createCellStyle();
            HSSFFont headerFont = workbook.createFont();
            headerFont.setBold(true);
            headerStyle.setFont(headerFont);
            headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
            headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            
            // Create date style
            HSSFCellStyle dateStyle = workbook.createCellStyle();
            dateStyle.setDataFormat(workbook.createDataFormat().getFormat("yyyy-mm-dd"));
            
            // Create currency style
            HSSFCellStyle currencyStyle = workbook.createCellStyle();
            currencyStyle.setDataFormat(workbook.createDataFormat().getFormat("$#,##0.00"));
            
            // Create headers
            Row headerRow = sheet.createRow(0);
            String[] headers = {"ID", "Name", "Date", "Amount", "Active"};
            
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
                cell.setCellStyle(headerStyle);
            }
            
            // Add sample data
            Object[][] data = {
                {1, "John Doe", new Date(), 1250.50, true},
                {2, "Jane Smith", new Date(), 2100.75, true},
                {3, "Bob Johnson", new Date(), 875.25, false},
                {4, "Alice Brown", new Date(), 3200.00, true}
            };
            
            for (int i = 0; i < data.length; i++) {
                Row row = sheet.createRow(i + 1);
                
                for (int j = 0; j < data[i].length; j++) {
                    Cell cell = row.createCell(j);
                    Object value = data[i][j];
                    
                    if (value instanceof String) {
                        cell.setCellValue((String) value);
                    } else if (value instanceof Integer) {
                        cell.setCellValue((Integer) value);
                    } else if (value instanceof Double) {
                        cell.setCellValue((Double) value);
                        if (j == 3) { // Amount column
                            cell.setCellStyle(currencyStyle);
                        }
                    } else if (value instanceof Date) {
                        cell.setCellValue((Date) value);
                        cell.setCellStyle(dateStyle);
                    } else if (value instanceof Boolean) {
                        cell.setCellValue((Boolean) value);
                    }
                }
            }
            
            // Add formula sheet
            HSSFSheet formulaSheet = workbook.createSheet("Formulas");
            Row row1 = formulaSheet.createRow(0);
            row1.createCell(0).setCellValue("Sum:");
            row1.createCell(1).setCellFormula("SUM('Sample Data'!D2:D5)");
            
            Row row2 = formulaSheet.createRow(1);
            row2.createCell(0).setCellValue("Average:");
            row2.createCell(1).setCellFormula("AVERAGE('Sample Data'!D2:D5)");
            
            // Auto-size columns
            for (int i = 0; i < headers.length; i++) {
                sheet.autoSizeColumn(i);
            }
            
            // Write to file
            try (FileOutputStream fos = new FileOutputStream(filename)) {
                workbook.write(fos);
            }
            
            System.out.println("Sample XLS file created: " + filename);
        }
    }
    
    public static void main(String[] args) {
        try {
            // Create sample file
            createSampleXLS("sample.xls");
            
            // Analyze the file
            XLSInfo info = analyzeXLSFile("sample.xls");
            
            System.out.println("\nFile Analysis:");
            System.out.println("Filename: " + info.filename);
            System.out.println("Number of sheets: " + info.numberOfSheets);
            System.out.println("Has macros: " + info.hasMacros);
            
            for (XLSInfo.SheetInfo sheet : info.sheets) {
                System.out.println("\nSheet: " + sheet.name);
                System.out.println("  Rows: " + sheet.rows);
                System.out.println("  Columns: " + sheet.columns);
                System.out.println("  Cells with data: " + sheet.cellsWithData);
                System.out.println("  Formulas: " + sheet.formulas);
                System.out.println("  Data types: " + sheet.dataTypes);
            }
            
            // Convert to CSV
            convertXLSToCSV("sample.xls", ".");
            
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Security Considerations

  • XLS files can contain macros with potential security risks
  • Validate file structure before processing
  • Be cautious with files from untrusted sources
  • Consider disabling macro execution in production environments
  • Use up-to-date libraries to handle known vulnerabilities
  • Implement proper input validation and sanitization

Modern Alternatives and Migration

  • XLSX: Modern Excel format with better compression and features
  • CSV: Simple text format for data exchange
  • ODS: Open Document Spreadsheet format
  • Google Sheets: Cloud-based spreadsheet solution
  • LibreOffice Calc: Open-source spreadsheet application

Best Practices

  • Always validate XLS files before processing
  • Use appropriate libraries for reading/writing XLS files
  • Handle encoding issues properly
  • Implement error handling for corrupted files
  • Consider memory usage when processing large files
  • Document any custom formatting or formulas used
  • Test compatibility across different Excel versions

Troubleshooting Common Issues

  • Encoding problems: Use appropriate character encoding
  • Formula errors: Validate formula syntax and references
  • Date formatting: Handle different date formats correctly
  • Large file performance: Use streaming readers for big files
  • Macro compatibility: Test macro functionality across versions
  • Cell limit issues: Be aware of XLS row/column limitations

File Information

File Description

Microsoft Excel CDF document

Category

Document

Extensions

.xls

MIME Type

application/vnd.ms-excel

Related File Types

Other file types in the Document category you might also need:

Start Analyzing XLS Files Now

Use our free AI-powered tool to detect and analyze Microsoft Excel CDF document files instantly with Google's Magika technology.

Try File Detection Tool