SUBMIT A FILE TYPE CONTACT US SUPPORT ABOUT US

What Is a DOC File? The Same 8 Bytes Start DOC, XLS and PPT Files

DOC files are Word documents saved in the Word 97 to 2003 format. Jump to your question below, or work through it in order.

43 min read Updated October 2026 Checked against sources and tests

What Is a DOC File? Word's binary format from Word 97 to Word 2003

Short answer

DOC files are Word documents saved in the format that Microsoft used from Word 97 to Word 2003. Every DOC file is a small file system packed into one file. It stores the text, the pictures and the page settings in separate streams.

The signature is shared. DOC files, XLS files and PPT files all start with the same 8 bytes, so the proof is a stream named WordDocument. In our tests of 25 damaged DOC files, the best readers returned all the text from 12, and a text pass found all of it in 20.

To check your DOC file, read the signature test. To open one, read how to open DOC files. If yours is damaged, start with the damage tests.

DOC files are Word documents in the binary format that Microsoft used from Word 97 to Word 2003. Word 2007 and later save DOCX files by default, and Word still opens DOC files.

Picture an email attachment called report.doc. It came from a school, a bank or an old client. It opens on one computer, and on another it shows junk or nothing at all. The ending is the same in both cases, and so is the file. What changed is the program that tried to read it.

FileInfo describes DOC files as word processing documents made by Word or exported from other word processors. They contain formatted text, pictures, tables, charts and print settings. Wikipedia adds that Microsoft has used the ending since 1983, and that Word 2007 replaced DOC with DOCX as the main format.

The name covers more than one format. Word for MS-DOS had its own DOC format. Word 97 through Word 2003 used a format built on OLE and the Compound File Binary container, says Wikipedia. That second format is the one this page tests.

Microsoft published a specification under its Open Specification Promise on February 15, 2008, says Wikipedia. Microsoft Learn lists the MS-DOC specification at revision 12.5, dated February 17, 2026. Wikipedia says it does not cover every feature, so some tools still rely on reverse engineering.

DOC file facts at a glance

Quick facts about DOC files
Property Value
Meaning Word processing documents saved by Word 97 to Word 2003
Ending .doc for documents and .dot for templates. PRONOM also lists .wbk, a backup of a Word document.
Made by Microsoft Word. LibreOffice, WPS Office and others can save DOC files too.
MIME type application/msword, says PRONOM
Apple type name com.microsoft.word.doc, says PRONOM
Starts with d0 cf 11 e0 ​a1 b1 1a e1, the same 8 bytes that XLS and PPT files use
Container Compound File Binary, with 512-byte sectors in all our DOC files
Word marker A stream named WordDocument that starts with 0xA5EC
Opens in Word, LibreOffice, WPS Office, Apple Pages and Google Docs, says FileInfo
Safe to open Looking at the text is low risk. Macros are the risk, so keep them off.

Wrong page? Modern Word files that end in .docx are in the DOCX file guide. Open-source documents are in the ODT file guide. Spreadsheets and slides have the same first bytes, and the XLS file guide and the PPT file guide cover them. Read-only documents are in the PDF file guide.

How Do You Know Your File Is a DOC File? The first 8 bytes are shared, so read the streams

The first 8 bytes do not prove a DOC file. DOC, XLS and PPT files all start with d0 cf 11 e0 a1 b1 1a e1. The proof is a stream named WordDocument, whose first two bytes are 0xA5EC.

Many pages call d0 cf 11 e0 a1 b1 1a e1 the signature of DOC files. It is the signature of the container, the Compound File Binary format. Our own earlier page on this site said OLECF, which is the same mistake. We built DOC, XLS and PPT files, and all three start with those 8 bytes.

The file command named all three Composite Document File V2 Document. Its answer added the author, the title and the times, and nothing that says Word. 7-Zip printed Type = Compound for all three. So neither tool separates a DOC file from a spreadsheet or a slide show.

A table of 14 files and the first 8 bytes of every one. Three Word files, an Excel file and a PowerPoint file all start with d0 cf 11 e0 a1 b1 1a e1. A DOCX and an ODT file saved as .doc start with 50 4b 03 04. An RTF file starts with the text {\rtf1, a web page with the text <!DOCTYP, a Word 2003 XML file with the text <?xml and a text file with a byte order mark. A DOC file with 52 bytes of mail header in front starts with the text X-Mailer. A DOC file with its signature set to zero starts with eight zero bytes, and an empty file has no bytes
The same 8 bytes start DOC, XLS and PPT files. The streams separate them.

The PRONOM entry identifies DOC files by more than the first bytes. Its entry checks the container, the stream named WordDocument and the text Word.Document.8 inside the stream named CompObj. Our DOC files had all three. The CompObj stream of our XLS file said Biff8 instead, and the PPT file said MS PowerPoint 97.

The script below does the same job with the Python standard library. It reads the container, lists the streams and finds WordDocument. Then it reads the Word header, called the FIB, and prints the problems it can see. Save it as check_doc.py and give it the name of your DOC file.

Check DOC files with Python
#!/usr/bin/env python3
"""check_doc.py: look inside a .doc file without opening Word.
Usage: python3 check_doc.py file.doc [more files]
Prints the first 8 bytes, what kind of file it is, the size, the streams
of a compound file, the Word header (FIB) fields and any problems found."""
import struct, sys

SIG = bytes.fromhex('d0cf11e0a1b11ae1')
END, FREE = 0xFFFFFFFE, 0xFFFFFFFF

def chain(fat, start, limit):
    out, seen = [], set()
    while start < 0xFFFFFFF0:
        if start in seen:
            return out, 'loop'
        if start >= len(fat):
            return out, 'outside FAT'
        seen.add(start); out.append(start); start = fat[start]
        if len(out) > limit:
            return out, 'too long'
    return out, None

def check(path):
    data = open(path, 'rb').read()
    print(f'{path}: {len(data):,} bytes, starts {data[:8].hex(" ")}')
    problems = []
    if not data:
        print('  empty file'); return ['empty file']
    if data[:4] == b'PK\x03\x04':
        print('  kind: ZIP-based (a DOCX or ODT renamed to .doc)'); return []
    if data[:5] == b'{\\rtf':
        print('  kind: RTF text'); return []
    head = data[:512].lstrip().lower()
    if head.startswith((b'<?xml', b'<html', b'<!doctype')):
        print('  kind: XML or HTML text'); return []
    if data[:8] != SIG:
        at = data[:65536].find(SIG)
        if at > 0:
            print(f'  signature found at offset {at}: extra bytes come before the file')
            return [f'signature at offset {at}']
        printable = sum(32 <= b < 127 or b in (9, 10, 13) for b in data[:2000]) / max(1, len(data[:2000]))
        print('  kind: plain text' if printable > 0.95 else '  kind: not a compound file (no signature)')
        return [] if printable > 0.95 else ['no compound file signature']
    if len(data) < 512:
        print('  too short for a compound file header'); return ['short header']
    major, shift = struct.unpack_from('<HxxH', data, 0x1A)[0], struct.unpack_from('<H', data, 0x1E)[0]
    if shift not in (9, 12):
        problems.append(f'sector shift {shift}')
        print('  header problem:', problems[-1]); return problems
    ss = 1 << shift
    nfat, dstart, _, cutoff, mfstart, nmf, difstart, ndif = struct.unpack_from('<IIIIIIII', data, 0x2C)
    # sector n lives at (n + 1) * ss
    def sector(n):
        off = (n + 1) * ss
        return data[off:off + ss] if off + ss <= len(data) else None
    nsect = len(data) // ss - 1
    if len(data) % ss:
        problems.append('size is not a multiple of the sector size')
    fatlocs = [x for x in struct.unpack_from('<109I', data, 0x4C) if x < 0xFFFFFFF0]
    fat = []
    for loc in fatlocs:
        s = sector(loc)
        if s is None:
            problems.append(f'FAT sector {loc} is past the end of the file'); continue
        fat += struct.unpack(f'<{ss // 4}I', s)
    if not fat:
        problems.append('no readable FAT'); print('  problems:', '; '.join(problems)); return problems
    dchain, err = chain(fat, dstart, nsect + 8)
    if err: problems.append(f'directory chain: {err}')
    dirdata = b''.join(sector(n) or b'' for n in dchain)
    if len(dirdata) < len(dchain) * ss:
        problems.append('directory goes past the end of the file')
    entries = []
    for i in range(0, len(dirdata) - 127, 128):
        e = dirdata[i:i + 128]
        nl = struct.unpack_from('<H', e, 64)[0]
        typ = e[66]
        if typ == 0 or nl < 2 or nl > 64: continue
        name = e[:nl - 2].decode('utf-16le', 'replace')
        entries.append((name, typ, struct.unpack_from('<I', e, 116)[0], struct.unpack_from('<Q', e, 120)[0]))
    if not entries:
        problems.append('directory is empty or unreadable')
        print('  problems:', '; '.join(problems)); return problems
    streams = [e for e in entries if e[1] == 2]
    print('  streams:', ', '.join(repr(e[0]) if ord(e[0][0]) < 32 else e[0] for e in streams))
    word = next((e for e in streams if e[0] == 'WordDocument'), None)
    if not word:
        names = {e[0] for e in streams}
        if 'Workbook' in names or 'Book' in names: print('  kind: Excel workbook (XLS), not a Word file')
        elif 'PowerPoint Document' in names: print('  kind: PowerPoint (PPT), not a Word file')
        elif any(n.startswith('__properties_version') for n in names): print('  kind: Outlook message (MSG)')
        else: print('  kind: compound file without a WordDocument stream')
        problems.append('no WordDocument stream'); return problems
    name, typ, start, size = word
    if size >= cutoff:
        ch, err = chain(fat, start, nsect + 8)
        if err: problems.append(f'WordDocument chain: {err}')
        body = b''.join((sector(n) or b'') for n in ch)[:size]
        if len(body) < size: problems.append('WordDocument is cut short')
    else:
        root = next(e for e in entries if e[1] == 5)
        rch, _ = chain(fat, root[2], nsect + 8)
        mini = b''.join(sector(n) or b'' for n in rch)
        mchain, _ = chain(fat, mfstart, nsect + 8)
        mfat = struct.unpack(f'<{len(b"".join(sector(n) or b"" for n in mchain)) // 4}I', b''.join(sector(n) or b'' for n in mchain)) if mchain else ()
        ch, err = chain(mfat, start, 100000)
        body = b''.join(mini[n * 64:n * 64 + 64] for n in ch)[:size]
    if len(body) < 12:
        problems.append('WordDocument stream is unreadable'); print('  problems:', '; '.join(problems)); return problems
    wident, nfib, _, lid, _, flags = struct.unpack_from('<6H', body, 0)
    print(f'  WordDocument: {size:,} bytes, wIdent {wident:#06x}, nFib {nfib:#06x}')
    if wident != 0xA5EC: problems.append('wIdent is not 0xA5EC')
    if nfib not in (0xC1, 0xD9, 0x101, 0x10C, 0x112): problems.append(f'nFib {nfib:#06x} is not in the list')
    table = '1Table' if flags & 0x200 else '0Table'
    print(f'  template: {bool(flags & 1)}, encrypted: {bool(flags & 0x100)}, picture: {bool(flags & 8)}, table stream: {table}')
    if table not in {e[0] for e in streams}: problems.append(f'{table} is missing')
    print('  problems:', '; '.join(problems) if problems else 'none found')
    return problems

if __name__ == '__main__':
    for p in sys.argv[1:]:
        try: check(p)
        except Exception as ex: print(f'  could not check: {ex}')
The answer for our good DOC file
samples/full.doc: 66,048 bytes, starts d0 cf 11 e0 a1 b1 1a e1
  streams: '\x01CompObj', '\x01Ole', 1Table, Data, '\x05SummaryInformation', WordDocument, '\x05DocumentSummaryInformation'
  WordDocument: 11,837 bytes, wIdent 0xa5ec, nFib 0x0101
  template: False, encrypted: False, picture: True, table stream: 1Table
  problems: none found

We tried the script on all 44 test DOC files. It flagged none of the 9 Word files and 19 of the 25 damaged copies. It named the kind of the 8 renamed files and of the XLS and PPT files. It cannot see a flipped bit in the text or the tables, because those leave the structure intact. The section on damaged DOC files lists all 25.

The answer for our DOC file with 52 bytes of mail header in front
damaged/d17-shifted.doc: 66,100 bytes, starts 58 2d 4d 61 69 6c 65 72
  signature found at offset 52: extra bytes come before the file
What files that are not DOC files show
Kind Where to look What you see
DOCX or ODT file Bytes 0 to 3 50 4b 03 04, the ZIP signature
RTF file The first bytes The text {\rtf1
Web page The first bytes The text <!DOCTYPE or <html
Word 2003 XML file The first bytes The text <?xml
XLS file The stream names Workbook, not WordDocument
Plain text file The entire file Readable text from byte 0
Empty file The size 0 bytes

Four more clues about your DOC file

The 7z l command It listed the streams of every compound file we tried. For our DOC file it showed WordDocument, 1Table, Data and the property streams.
The olefile module It opened our DOC, XLS and PPT files the same way. The root entry gave a different CLSID for every kind: 00020906 for DOC, 00020810 for XLS and 64818D10 for PPT.
The ending Eight files in our set were saved under the ending .doc without being Word files. Read the bytes before you trust the ending.
The Word header Every DOC file we built had 0xA5EC in the first two bytes of WordDocument. The script treats any other value as a problem.

What Is Inside a DOC File? A header, tables, a directory and streams

A DOC file is a small file system. A 512-byte header points to sectors, a table says which sectors belong together and a directory names the streams. Word keeps the text in WordDocument and the layout in 1Table or 0Table.

Think of a filing cabinet with a card index. The header says where the index is. The index lists the drawers, which are called streams. Every drawer is a chain of 512-byte sheets, which are called sectors. Word opens the WordDocument drawer first, because its first bytes show Word what it is dealing with.

A diagram of one DOC file of 66,048 bytes. The bytes are grouped by stream: WordDocument with 11,837 bytes, 1Table with 10,515 bytes, Data with 38,767 bytes, four small streams with 678 bytes and 4,251 bytes of header, allocation table, directory and padding. Three steps lead from the file to the text. First read the 512-byte header and the signature. Second read the directory to find WordDocument. Third read the Word header, which starts with 0xA5EC and contains the flag word that names 1Table or 0Table
One DOC file of 66,048 bytes, drawn from the streams that 7-Zip listed.

The sizes in the figure come from one file we built, with 40 paragraphs, a list, a table and a picture. The streams add up to 61,797 bytes. The rest of the DOC file is the header, the allocation table, the directory and padding to full sectors. Wikipedia on the Compound File Binary format says sectors are 512 or 4,096 bytes, and all our DOC files used 512.

The container header

Fields of the container header we used
Field Where Value in our files
Signature byte 0 d0 cf 11 e0 ​a1 b1 1a e1
Major version byte 26 3, which means 512-byte sectors
Byte order byte 28 fe ff, little endian
Sector shift byte 30 9, because 2 to the 9th power is 512
First directory sector byte 48 A sector number, 126 in our DOC file
Small stream cutoff byte 56 4,096 bytes in all our DOC files

We read these positions from our own files, and the script found no problem in any of our 9 good DOC files. Wikipedia and Microsoft Learn do not print them in the pages we could fetch. We read no header from a file made by Word.

The Word header at the start of WordDocument

Fields of the Word header that the script reads
Field Where What it says
wIdent bytes 0 and 1 Must be 0xA5EC, says Microsoft
nFib bytes 2 and 3 The version number. Microsoft lists 0x00C1, 0x00D9, 0x0101, 0x010C and 0x0112. Ours were 0x0101.
Flag word bytes 10 and 11 Template, incremental save, picture, encrypted and table stream bits

Microsoft Learn says wIdent must be 0xA5EC. It says the bit named fEncrypted marks an encrypted or obfuscated document, and the bit named fWhichTblStm selects 1Table when it is 1 and 0Table when it is 0. In our full file the flag word was 12f8, with the table bit set. Our template read 12f9, and our password-protected file read 13f8.

The page for the Fib structure adds that nFib has five allowed values, and the rest of the header depends on which one it is. Word needs this header to find the text. When we set the first sector of WordDocument to zero, LibreOffice, antiword, catdoc and wvText all returned nothing. When we set only wIdent to zero, LibreOffice refused the DOC file, while antiword and wvText still returned all the text. The damage tests show the rest.

Where the text, the pictures and the names live

The text is stored in WordDocument. Microsoft says it is stored as 16-bit characters when the fCompressed bit is 0, and as 8-bit characters when the bit is 1, on the FcCompressed page. LibreOffice wrote our text as 16-bit characters, even for simple English. So you can see it with a text tool, but only if the tool reads 16-bit text.

The pictures are stored in the Data stream. Our 38,520-byte PNG was stored in one piece in a file that LibreOffice wrote, and the five lines below pulled it out with the same SHA-256 hash. We did not try this on a file made by Word, which may store pictures in other formats.

Pull a PNG picture out of a DOC file
import olefile
data = olefile.OleFileIO('report.doc').openstream('Data').read()
start = data.find(b'\x89PNG\r\n\x1a\n')
end = data.find(b'IEND', start) + 8
open('picture.png', 'wb').write(data[start:end])

The author, title, comments and times are stored in the SummaryInformation stream. The section on safety shows how to read them.

Which Kind of DOC File Do You Have? Documents, templates and password-protected files

DOC files come in a few kinds: documents, templates and password-protected files. The kind is stored in one 16-bit flag word at the start of WordDocument, so you can read it without opening the file in Word.

The ending .doc covers them all. A template gets the ending .dot, and PRONOM also lists .wbk, which Word uses for backup copies. Inside a DOC file, the kind is a set of bits in the flag word at bytes 10 and 11 of WordDocument.

Kinds of DOC file and what we made
Kind How to see it Our files
Document The ending .doc and the Word header. No template bit. Made 7 files
Template The ending .dot and the lowest bit of the flag word set to 1. Made 1 file
Password-protected The encrypted bit of the flag word, 0x0100, set to 1. Made 1 file
With pictures A stream named Data, and the picture bit 0x0008 set to 1. Made 4 files
Word backup The ending .wbk, which PRONOM lists beside .doc. Not made
Word for MS-DOS An older format with its own layout, says Wikipedia. Not made

We read the flag word of four files. Next to full.doc, every one of the other three differs by one bit, set for a picture, a template or encryption.

Flag words of four DOC files we built
File Flag word What it shows
text.doc 12f0 No template, no picture, not encrypted
full.doc 12f8 Picture bit set
full.dot 12f9 Picture bit and template bit set
full-pw.doc 13f8 Picture bit and encrypted bit set

Microsoft Learn names the bits fDot, fHasPic and fEncrypted on the FibBase page. We matched them to the files by building one change at a time. The check script prints all three.

A picture means a Data stream

All four of our DOC files with pictures had a Data stream of 38,767 bytes, and none of the other five had one. A DOC file with no Data stream can still have pictures that Word draws itself, so use the bit as the proof and the stream as a hint.

Older Word formats

Wikipedia says Word for MS-DOS used its own DOC format, and the OLE-based format started with Word 97. PRONOM lists Word 6.0 and 95 files as the format before this one. We built none of them. If an old file fails every test on this page, open it in LibreOffice or Word and save it again as a new DOC or DOCX file.

What Do 44 Test DOC Files Show? 9 good DOC files, 25 damaged copies and five readers

No single reader returned all the text from our good DOC files. LibreOffice did it for 6 of 7 files that contain text, antiword and a text pass for 5, wvText for 4 and catdoc for 3. Then we tried the same readers on 25 damaged copies.

We found no public set of DOC files with known content, and files from offices have text we cannot compare. So we built our own in October 2026. Every full file got the same 52 test items: 40 paragraphs, 9 table cells and 3 list items. A reader counted as returning all the text only when all 52 items came back.

We damaged copies in 25 ways and tried five readers on all 44 files. The readers were LibreOffice 24.2.7, antiword 0.37, catdoc 0.95, wvText from wv 1.2.9 and GNU strings 2.42. 7-Zip 23.01 listed the streams. olevba 0.60.2 found no VBA or XLM macros in any of the 9 good DOC files.

We did not test any DOC file made by Word. All our DOC files came from LibreOffice 24.2.7, which wrote them in the Word 97 format. We did not use Word, Notepad, WordPad, Pages, Google Docs or WPS Office. We left out Fast Saved files and files with macros. We also left out Word 6 and 95 files and the SysTools and Freeviewer tools. Word may write other values than LibreOffice does.

44 files tested
9 good DOC files we built
25 damaged copies
5 readers used

The 9 good DOC files we built

The 9 good DOC files and what they test
DOC file What it is
text.doc 40 paragraphs of English text. 25,088 bytes.
full.doc 40 paragraphs, a table of 9 cells, a list of 3 items and a PNG picture. 66,048 bytes.
multi.doc 5 lines in Hindi, Arabic, Chinese, Russian and English. 18,432 bytes.
big.doc 4,000 numbered lines. 768,000 bytes.
empty.doc No text at all. Already 18,432 bytes.
pic.doc One picture and no text. 57,344 bytes.
tableonly.doc A table of 9 cells and nothing else. 19,968 bytes.
full.dot The full file saved as a template. 66,048 bytes.
full-pw.doc The full file with a password to open. 66,048 bytes.

Two of the 9 files, empty.doc and pic.doc, have no text. All five readers returned nothing from them, which is correct. So the counts below use the 7 files that do have text.

Which readers returned all the text from 7 good DOC files
Reader Files read Note
LibreOffice 24.2.7 6 of 7 Failed only on the password-protected file. It also read the DOCX, RTF, HTML, text, XML and ODT files that we had saved as .doc.
antiword 0.37 5 of 7 Refused small files with the words text stream too small, so it missed multi.doc. It said encrypted documents are not supported.
catdoc 0.95 3 of 7 Dropped table cells: 43 of 52 items from full.doc and 0 of 9 from tableonly.doc.
wvText 1.2.9 4 of 7 Returned 4 of the 5 lines in multi.doc and none of the 9 table cells in tableonly.doc.
strings 2.42 5 of 7 Found 16-bit Latin text only, so 1 of 5 lines in multi.doc. It stood in for Notepad.
A grid of five readers against the 9 good DOC files. LibreOffice returned all the text from every file except full-pw.doc, which has a password. antiword refused multi.doc, empty.doc and pic.doc as too small and refused full-pw.doc as encrypted, and read the other five. catdoc read text.doc, multi.doc, big.doc, empty.doc and pic.doc, and returned 43 of 52 items from full.doc and full.dot, none of the cells from tableonly.doc and nothing from full-pw.doc. wvText read text.doc, full.doc, big.doc, empty.doc, pic.doc and full.dot, and returned 4 of 5 lines from multi.doc, none of the cells from tableonly.doc and nothing from full-pw.doc. strings found all the text in text.doc, full.doc, big.doc, tableonly.doc and full.dot, 1 of 5 lines in multi.doc and nothing in full-pw.doc
LibreOffice read 6 of 7, antiword and strings 5, wvText 4 and catdoc 3.

The password-protected file shows how strict the format is. All five readers returned nothing from it, and 7-Zip still listed its streams. The text was not hidden by a clever trick. It was scrambled, and no reader asked for a password in headless mode.

The 25 damaged DOC files

We damaged copies of full.doc in 25 ways, with one kind of damage in every case. The full list of 25 cases gives the fix for every one. The table counts the cases where at least one reader returned all 52 items, and the cases where a text pass did.

Damaged DOC files that gave back all 52 items
Damage (cases) Before After Text pass
Container header, table or directory damaged (7) 3 4 7
Word header damaged (4) 3 3 4
Extra bytes or a bad transfer (5) 4 5 5
Cut file or lost end (4) 0 0 2
Flipped bit (3) 2 2 2
Overwrite (1) 0 0 0
Empty file (1) 0 0 0
All 25 cases 12 14 20

Before repair means at least one of LibreOffice, antiword, catdoc and wvText returned all 52 items. After repair means the same check after our repair script. A text pass means strings found all 52 items. The script made 7 fixes that worked, and the text pass beat every word processor reader.

Text outlives the container A text pass found all 52 items in 20 of the 25 damaged DOC files. The best word processor readers found them in 12. Where the file system inside the DOC file was broken, the characters were often still in place.
Readers disagree With the first 512 bytes zeroed, only catdoc among the four converters returned all 52 items. With the sector size changed, only antiword did. With the table flag flipped, only wvText did. No reader was the best on every file.
A flipped bit passes quietly One flipped bit in the body text changed Paragraph 20 to Peragraph 20. Four readers returned the DOC file with no error. Flipped bits in the table stream and the author name changed nothing we could see.
Half a stream looks like success After 4,096 random bytes were written over WordDocument, four readers returned the first 27 of 52 items with no warning. wvText returned nothing.

Read the counts with care. We damaged small DOC files with simple breaks. Failing drives, bad downloads and half-finished copies do messier harm. The numbers show how these readers behave with these files, and they are not rates for all DOC files.

What Does Our Expert Say About DOC Files? A note from Neeraj Singh on getting the text out first

Pull the text out of a damaged DOC file before you try to repair it. In our tests, a text pass found all the text in 20 of 25 damaged DOC files, and the best word processor readers found it in 12.

Neeraj Singh

Expert insight

“A DOC file keeps its text apart from its layout, so a file that Word refuses can still contain every word. In our tests, a plain text pass found all the text in 20 of 25 damaged DOC files, and the best converter found it in 12. Work on a copy, pull the text out first and only then try to repair the rest.”

Neeraj Singh Manager, Tech Support & Operations 19+ years fixing Windows and system errors

Why the text survives

The text is stored in WordDocument, apart from the layout in 1Table and the pictures in Data. Damage to the container header, the allocation table or the directory stops readers from finding the stream. The characters are still in the DOC file. Our text pass did not need the container, so it found them anyway.

A text pass is not a repair. Formatting, tables and pictures are gone, and so is the order of the text if the DOC file is out of order. It also cannot say whether a letter is right. The text pass on the DOC file with one flipped bit returned 51 of 52 items and no error, the same as the word processor readers.

Microsoft's page on damaged documents points the same way. It lists Recover Text from Any File, which keeps the text and loses formatting, graphics and fields. It also lists copying the content into a new document and opening the DOC file in Notepad to remove the extra code. We did not test Word or Notepad, so we cannot say how they would do on our DOC files.

Our script missed 6 of the 25 damaged DOC files. They were the three flipped bits, the overwritten stream and the two files with extra bytes at the end. Their containers were sound, so the script had nothing to flag. Only a comparison with a good copy finds the first four.

Keep the original. Work on copies of DOC files and keep the first one. If a repair goes wrong, you can start again. Our own repair script changed 8 of the 25 files and fully fixed 7. The eighth, with its Word header zeroed, was changed and still unreadable.

How Do You Open DOC Files? Word, LibreOffice, command line readers and passwords

Double-click the DOC file to open it in Word. Without Word, open it in LibreOffice, which returned all the text from 6 of 7 of our good DOC files. The command line readers all failed on at least one file.

Opening a DOC file to read it is a small job. Most trouble comes from a file that is not what its ending says, a file with a password or a file that is damaged. The sections below cover those three cases in order.

Ways to open DOC files
Program What it does What we saw
Microsoft Word Opens DOC files, and Wikipedia says Word can still create them Not tested
LibreOffice Free office suite for Windows, Mac and Linux, says FileInfo 6 of 7 files
WPS Office Listed by FileInfo for Windows, Mac, Linux and Android Not tested
Apple Pages Listed by FileInfo for Mac and iOS, and by Wikipedia with some limits Not tested
Google Docs Opens DOC files in a browser, says FileInfo Not tested
antiword Command line reader for DOC files 5 of 7 files
wvText Command line reader from the wv library, which AbiWord uses 4 of 7 files
catdoc Command line reader that prints the text 3 of 7 files

Open a DOC file in Word

  1. Double-click the DOC file, or open Word and choose File, then Open.
  2. If Word says the file is damaged, go to the damaged files section before you try anything else.
  3. To get a modern copy, choose File, then Save As, then select DOCX. We did not test these steps.

Open a DOC file without Word

LibreOffice is the best free choice we tested. It opened 6 of 7 good DOC files with all their text. It also read the files that we had saved as .doc but were really DOCX, RTF, HTML, text, XML or ODT. Open the DOC file, or use the first command below to write its text to a file.

Read DOC files without Word
# one line for every reader we tested
soffice --headless --convert-to "txt:Text (encoded):UTF8" report.doc
antiword -m UTF-8.txt report.doc
catdoc -d utf-8 report.doc
wvText report.doc report.txt
# a text pass, for damaged files (8-bit, then 16-bit little endian)
strings -n 4 report.doc
strings -n 4 -el report.doc

Every reader has a weak spot. Antiword refuses small files with the words text stream too small, and it said encrypted documents are not supported. Catdoc dropped every table cell in tableonly.doc and 9 of 52 items in full.doc. WvText returned no cells from the table-only file. Try a second reader when the first one gives you less than you expect.

Before you try any of them, list the streams. 7-Zip printed Type = Compound for all our DOC files and named the streams, WordDocument among them. If WordDocument is missing, you do not have a DOC file, and the signature test says what you do have.

What 7-Zip printed for our full DOC file (shortened)
7z l full.doc
Type = Compound
Physical Size = 66048
Sector Size = 64
   Date      Time    Attr         Size   Compressed  Name
                    .....          106          128  [1]CompObj
                    .....           20           64  [1]Ole
                    .....        10515        10752  1Table
                    .....        38767        38912  Data
                    .....          380          384  [5]SummaryInformation
                    .....        11837        12288  WordDocument
                    .....          172          192  [5]DocumentSummaryInformation
7 files

Open a password-protected DOC file

A password-protected DOC file has the encrypted bit set in its flag word. In our test, LibreOffice, antiword, catdoc, wvText and the text pass all returned nothing from it, though 7-Zip still listed its streams. antiword said encrypted documents are not supported.

You need the password. With the right one, msoffcrypto-tool 6.0.0 decrypted our DOC file into a normal DOC file, and LibreOffice and antiword then returned all 52 items from it. With a wrong one, it stopped with an InvalidKeyError and the words Failed to verify password.

Decrypt a DOC file with the password
import msoffcrypto
f = msoffcrypto.OfficeFile(open('locked.doc', 'rb'))
f.load_key(password='your-password')
f.decrypt(open('unlocked.doc', 'wb'))

We do not cover password guessing. We did not test any tool that finds a lost password, so this page has no advice on that. If you forgot the password, ask the person who sent the DOC file, or look for an older copy without one.

Free viewers and reference pages

These cards link to four outside pages. One is a Windows viewer for DOC files and one is a Windows tool for damaged Word files. The other two are Microsoft's page on damaged documents and the Wikipedia article on DOC files.

Freeviewer DOC Viewer

Opens DOC files on Windows

Free and paid options

SysTools Word Recovery

Repairs damaged DOC and DOCX files

Trial previews only

Microsoft: damaged documents

Steps to try in Word

Microsoft page

DOC on Wikipedia

History and formats

Wikipedia page

Freeviewer describes a Windows viewer that opens DOC files without Microsoft Office. It shows embedded images, hyperlinks and rich text, opens one file at a time and says it works on your computer and does not upload files. The page says the software is free to use after download and also lists a paid option, so read its limits before you rely on it. We did not start it.

SysTools describes a Windows tool, version 4.2, that repairs damaged Word files. Its page lists separate downloads for DOCX and DOC files. It previews recovered data as rich text or plain text. The page says the free trial only previews and cannot save, and that it needs .NET Framework 4.5. It also says Word 2007 to 2021 must be installed to preview files. We did not start it.

Tip. You do not need a paid tool to read the words in a damaged DOC file. The free text pass found all the text in 20 of our 25 damaged copies.

Are DOC Files Safe to Open? Macros, the internet and what the file says about you

Reading the text of a DOC file is low risk. Macros are the danger, because they can start code when you enable them. DOC files also store the author name and save times, so check them before you send a file out.

A DOC file is a container. It can store text, pictures, form fields and small programs called macros. The text and pictures do nothing until you read them. A macro starts working when you choose to enable it, so the safe habit is to leave macros off unless you know the sender.

We built our test DOC files in LibreOffice, so none of them had macros. olevba 0.60.2 found no VBA or XLM macros in our 9 good DOC files. We did not test a DOC file with a macro, so we have no result to show for one.

What to check before you open a DOC file
Check What to do What we saw
Macros List them with olevba before you open the DOC file None found in our 9 good DOC files
Where it came from Windows Word blocks macros in files from the internet Microsoft page, not tested
Author and times Read them with olefile or the file command Both printed our test author
Hidden text Remove them with Document Inspector Microsoft page, not tested
The file kind Use the signature test Named all 10 non-Word files

What Microsoft says about macros and the internet

Microsoft's page on blocked macros says Windows marks files from the internet with a Mark of the Web, and that Office on Windows blocks macros in those files by default. Users then see a SECURITY RISK banner without an Enable content button. The change began rolling out in Current Channel version 2206 on July 27, 2022.

The same page says the change does not apply to Office on Mac, on the web, on Android or on iOS. It also says perpetual versions like Office 2019 and LTSC 2021 are not affected by the new default. It does not name DOC files. It talks about Office files in general.

Microsoft's page on file block names the DOC format directly. It lists Word 97, Word 2003 and later binary documents and templates, with the endings .doc and .dot. An administrator can block those files from opening, or open them in Protected View. If you manage computers, this setting is the one to look at.

What a DOC file says about you

The SummaryInformation stream stores the title, author, comments, template, last-saved-by name and creation and save times. Our full file had a 380-byte stream. The file command printed all of it, and so did three lines of Python.

Read the author and times of a DOC file
import olefile
m = olefile.OleFileIO('report.doc').get_metadata()
print(m.author, m.last_saved_by, m.create_time)
The answer for our full DOC file
b'Test Author' b'Test Editor' 2026-10-19 08:00:00

Microsoft's page on Document Inspector says the inspector removes comments, revision marks, document properties and personal information like the author and last-saved-by names, headers, footers, watermarks and hidden text. It adds that it cannot find hidden text made in other ways, like white text on a white background. We did not test it.

Do not enable content for strangers. If a DOC file from someone you do not know asks you to enable editing or enable content, close it. Text you can read without clicking anything is safe to read.

Why Will Your DOC File Not Open? Twenty-five damage tests, and the repairs that worked

DOC files that will not open usually have a damaged container, and the text is usually still inside. In our 25 damaged cases, a reader returned all the text from 12 as they were and from 14 after our repair script. A text pass found all of it in 20.

We broke copies of full.doc in 25 ways and tried the readers before and after repairs. The chart shows what the readers could do. Green means all 52 items came back, amber means some did and red means none did.

A grid of 25 damage tests. Before any repair, at least one of four converters returned all 52 test items from 12 damaged copies, some from 2 and none from 11. After our repair script, all 52 items came back from 14, some from 2 and none from 9. A text pass with strings found all 52 items in 20 copies, some in 3 and none in 2. The fixes range from writing the 8 signature bytes back to downloading the file again.
25 tests. Green is all 52 items back, amber is some and red is none.
Damage we met and what fixed it
Damage (cases) What you see and the fix
Cut short (4) All four converters refused it. The text pass found all 52 items in two files, 31 in one and none in the file cut in half. Fix: Download again, or use the text pass.
Signature zeroed (1) The same refusal from three converters. Only catdoc returned the text. Fix: Write the 8 bytes back.
First 512 bytes zeroed (1) Only catdoc returned the text. The text pass found all 52 items. Fix: Use catdoc or the text pass.
Wiped sector (4) All four converters refused it. 7-Zip could not list the streams in three of them. The text pass found all 52 items. Fix: Use the text pass.
Sector size or table loop (2) Sector size: only antiword read it. Table loop: all four refused it. Fix: Write 9 back at byte 30, or point the entry at the next sector.
Header values changed (3) wIdent zero: LibreOffice refused it. nFib changed: no reader complained. Table flag flipped: LibreOffice and antiword refused it. Fix: Write 0xA5EC back, or flip the table bit back.
Bytes in front (1) Only catdoc returned the text. Fix: Cut the bytes before d0 cf 11 e0.
Transfer or resave (2) Transfer: every 0A became 0D 0A, and all four refused it. UTF-8 resave: only catdoc read it. Fix: Replace 0D 0A with 0A. The UTF-8 resave cannot be undone.
Extra bytes at the end (2) LibreOffice and wvText returned all the text. antiword refused both. Fix: Use LibreOffice or wvText.
Flipped bit (3) No reader complained. The body text bit changed one letter. The others changed nothing we could see. Fix: Only a good copy shows it.
Stream overwritten (1) Four readers returned the first 27 of 52 items. wvText returned none. Fix: Use a good copy.
Empty file (1) Nothing to read. Fix: Download again.

The repairs, in small patches

Always work on a copy. The dd option conv=notrunc matters: without it, dd cuts the DOC file after the bytes it writes and destroys the rest. The three patches below fixed our signature, mail header and text-mode cases. In all three, the fixed copy was byte for byte the same as the file we started from.

Three small repairs we tested, on copies of the DOC files
# work on copies, never on the original
# 1. signature set to zero: write the 8 bytes back
cp broken.doc fixed-1.doc
printf '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1' | dd of=fixed-1.doc bs=1 seek=0 conv=notrunc
# 2. bytes in front: check_doc.py said the signature is at offset 52
tail -c +53 broken.doc > fixed-2.doc
# 3. text-mode transfer: change every 0D 0A back to 0A
python3 -c "d=open('broken.doc','rb').read().replace(b'\r\n',b'\n'); open('fixed-3.doc','wb').write(d)"

The script below adds four more fixes. They are a wrong sector size, a table entry that points to itself, a wrong wIdent and a flag that points to a missing table stream. It prints every fix it makes, writes a new file and never touches the original. In all 7 cases it fixed, the result matched the original byte for byte.

Repair DOC files with Python
#!/usr/bin/env python3
"""repair_doc.py: small, safe fixes for a damaged .doc. Writes a new file, never touches the original.
Usage: python3 repair_doc.py damaged.doc fixed.doc
Fixes tried, in order: junk before the file, wiped signature, wrong sector shift, a FAT entry that
points to itself, a wrong wIdent, a table-stream flag that points to a missing stream, and a text-mode
transfer (0D 0A back to 0A). Every fix is printed. It cannot rebuild a wiped FAT, directory or FIB."""
import struct, sys
SIG = bytes.fromhex('d0cf11e0a1b11ae1')

def parse(b):
    if len(b) < 512: return None
    ss = 1 << struct.unpack_from('<H', b, 0x1E)[0] if struct.unpack_from('<H', b, 0x1E)[0] in (9, 12) else None
    if not ss: return None
    sect = lambda n: b[(n + 1) * ss:(n + 2) * ss]
    fat = []
    for loc in struct.unpack_from('<109I', b, 0x4C):
        if loc < 0xFFFFFFF0 and len(sect(loc)) == ss:
            fat += list(struct.unpack(f'<{ss // 4}I', sect(loc)))
    if not fat: return None
    def chain(s):
        out = []
        while s < 0xFFFFFFF0 and s < len(fat) and s not in out and len(out) < 100000:
            out.append(s); s = fat[s]
        return out
    ds = struct.unpack_from('<I', b, 0x30)[0]
    ents = []
    for n in chain(ds):
        d = sect(n)
        for i in range(0, len(d) - 127, 128):
            e = d[i:i + 128]; nl = struct.unpack_from('<H', e, 64)[0]
            if e[66] and 2 <= nl <= 64:
                ents.append((e[:nl - 2].decode('utf-16le', 'replace'), e[66], struct.unpack_from('<I', e, 116)[0], struct.unpack_from('<Q', e, 120)[0]))
    return dict(ss=ss, fat=fat, chain=chain, ents=ents, sect=sect)

def repair(b):
    log = []
    if len(b) % 512 and b'\r\n' in b and (b.replace(b'\r\n', b'\n')[:8] == SIG) and len(b.replace(b'\r\n', b'\n')) % 512 == 0:
        b = b.replace(b'\r\n', b'\n'); log.append('replaced 0D 0A with 0A (undo a text-mode transfer)')
    at = b[:65536].find(SIG)
    if at > 0:
        b = b[at:]; log.append(f'removed {at} bytes in front of the signature')
    if len(b) >= 512 and b[:8] != SIG and b[0x1C:0x1E] == b'\xfe\xff' and struct.unpack_from('<H', b, 0x1A)[0] in (3, 4):
        b = SIG + b[8:]; log.append('wrote the signature back')
    if len(b) >= 512 and b[:8] == SIG:
        shift = struct.unpack_from('<H', b, 0x1E)[0]; major = struct.unpack_from('<H', b, 0x1A)[0]
        want = 9 if major == 3 else 12
        if shift != want and len(b) % (1 << want) == 0:
            b = b[:0x1E] + struct.pack('<H', want) + b[0x20:]; log.append(f'sector shift {shift} set to {want}')
        p = parse(b)
        if p:
            ba = bytearray(b)
            used = sum(1 for x in p['fat'] if x != 0)
            for n, nx in enumerate(p['fat']):
                if nx == n and used > 4:
                    # find the FAT sector and the entry that stores n
                    per = p['ss'] // 4; fl = [x for x in struct.unpack_from('<109I', b, 0x4C) if x < 0xFFFFFFF0]
                    off = (fl[n // per] + 1) * p['ss'] + (n % per) * 4
                    ba[off:off + 4] = struct.pack('<I', n + 1); log.append(f'FAT entry {n} pointed to itself, set to {n + 1}')
            b = bytes(ba); p = parse(b)
            w = next((e for e in p['ents'] if e[0] == 'WordDocument'), None) if p else None
            if w and w[3] >= struct.unpack_from('<I', b, 0x38)[0]:
                ch = p['chain'](w[2]); first = (ch[0] + 1) * p['ss']
                ba = bytearray(b)
                if struct.unpack_from('<H', b, first)[0] != 0xA5EC:
                    ba[first:first + 2] = struct.pack('<H', 0xA5EC); log.append('wIdent set back to 0xA5EC')
                fl = struct.unpack_from('<H', ba, first + 10)[0]
                names = {e[0] for e in p['ents']}
                cur = '1Table' if fl & 0x200 else '0Table'; other = '0Table' if cur == '1Table' else '1Table'
                if cur not in names and other in names:
                    ba[first + 10:first + 12] = struct.pack('<H', fl ^ 0x200); log.append(f'table flag now points to {other}')
                b = bytes(ba)
    return b, log

if __name__ == '__main__':
    data = open(sys.argv[1], 'rb').read()
    out, log = repair(data)
    for l in log: print('fix:', l)
    if not log: print('nothing to fix with these rules')
    open(sys.argv[2], 'wb').write(out)
The answer for our DOC file with 52 bytes of mail header in front
fix: removed 52 bytes in front of the signature

The script cannot rebuild a wiped table, directory or Word header sector. On our DOC file with the zeroed Word header sector, it set back wIdent and the table flag. All four converters still returned nothing, because the rest of that sector was still zero.

A text pass for the files that stay shut

When the container is too damaged to repair, read the text straight out of the bytes. LibreOffice stored our text as 16-bit characters, so the 16-bit mode of strings finds it. On the DOC file with its directory sector zeroed, every word processor reader failed and the first command still wrote all 40 paragraphs to text.txt.

Pull the text out of a damaged DOC file
strings -n 4 -el damaged.doc > text.txt
grep -c "^Paragraph" text.txt
The answer for our DOC file with its directory sector zeroed
40

The text pass has limits. It returns style names and other short strings with the text. It drops formatting and pictures. It finds only characters that fit in the 16-bit or 8-bit modes you choose. In our multi.doc, it found 1 of 5 lines, because the Hindi, Arabic, Chinese and Russian lines are not Latin. For those, use LibreOffice with the repaired copy.

What the tools could not fix

First 512 bytes set to zero Our script cannot rebuild a header. catdoc and the text pass still returned all 52 items, so copy the text out and start a new document.
Wiped table, directory or Word header sector The word processors refused all four files. The text was in the DOC file, and only the text pass found it. We did not try to rebuild the tables.
Flipped bits The three copies opened with no error. One bit changed Paragraph 20 to Peragraph 20. Only a comparison with a good copy finds that.
Overwritten stream 4,096 random bytes over WordDocument left 27 of 52 items. The rest is gone. The fix is a good copy.
Files cut in half or at 90 percent The half file gave nothing, and the other gave 31 of 52 items to the text pass. A download that stops part way looks like this.
UTF-8 resave Bytes that are not valid UTF-8 were swapped for the replacement character, ef bf bd, and the DOC file grew from 66,048 to 101,764 bytes. The first copy is the only fix.
Extra bytes at the end We added 1,048,576 zero bytes to one copy and a second DOC file to another. LibreOffice and wvText returned all the text from both.

Compare before you celebrate. After a repair, compare the text with the original if you have it. A file that opens is not always a file that is right, and one bad letter went through every reader in our tests.

How Do You Convert a DOC File to Another Format? DOCX, ODT, PDF, RTF, HTML and text, checked by count

Convert DOC files with LibreOffice from the command line, or with Save As in Word. In our tests, LibreOffice kept all 52 items in DOCX, ODT, PDF, RTF, HTML and text, and the picture came out byte for byte the same in DOCX and ODT.

Converting a DOC file reads the document and writes it again in another format. A good conversion keeps the words, the table and the picture. We converted full.doc six ways with LibreOffice 24.2.7 and counted the 52 items in every output.

What the conversion routes gave
Format Bytes What we saw
DOCX 48,301 All 52 items. The picture was byte for byte the same.
ODT 69,222 All 52 items. The picture was byte for byte the same.
PDF 40,125 All 52 items, read back with pdftotext.
RTF 117,866 All 52 items. Bigger than the DOC file.
HTML 9,319 All 52 items. The picture came out as a separate 38,520-byte PNG.
Text 3,114 All 52 items. Formatting and the picture are gone.
Convert DOC files with LibreOffice
soffice --headless --convert-to docx report.doc
soffice --headless --convert-to pdf report.doc
soffice --headless --convert-to odt report.doc
soffice --headless --convert-to rtf report.doc
soffice --headless --convert-to html report.doc
soffice --headless --convert-to "txt:Text (encoded):UTF8" report.doc

The source file was 66,048 bytes. DOCX was the smallest output that kept the formatting. PDF was smaller still, and it cannot be edited as a document. We did not test Word, so we cannot say how its conversion differs.

Do not trust a finished conversion on its own

A converter converts, and a count shows whether it did the job. We counted the items in every output. Do the same with your files: compare the number of pages, the table cells and the pictures with the original.

Does the picture survive?

In DOCX and ODT, the picture was stored as the same 38,520 bytes as the PNG we put in. In HTML, it was saved as a separate PNG file next to the page, so move both files together. We did not try other picture formats.

DOC to DOCX in bulk

The command accepts several files, so soffice --headless --convert-to docx --outdir out *.doc converts an entire folder. We converted 3 files in one call, and the sizes matched the single conversions. The next section compares sizes. We did not test a folder with hundreds of files.

Keep the DOC file. Convert a copy. If the output looks wrong, the DOC file is the only place the original layout lives.

What Is the Difference Between DOC and DOCX? Seven pairs, and how much smaller DOCX came out

DOCX is the newer format and DOC is the older one. In our seven pairs, the DOCX output was 18 to 93 percent smaller than the DOC file for the same content. A DOCX file also does not show its text to a plain text pass.

The Wikipedia history of DOC says Word 2007 made the Office Open XML format, which uses the ending .docx, the default and replaced the binary format. Word can still create and open DOC files. FileInfo dates the change to Word 2007 as well.

DOC and DOCX side by side
Item DOC DOCX
Made by Word 97 to Word 2003 Word 2007 and later
Format Compound File Binary A ZIP file of XML parts
First bytes d0 cf 11 e0 ​a1 b1 1a e1 50 4b ​03 04
Text pass Found the text in 20 of 25 damaged DOC files Found nothing in our renamed DOCX, because ZIP packs the text
Empty file About 18 KB About 8 KB

We made the DOCX files by converting seven of our DOC files with LibreOffice, so the sizes show what that program writes. A DOC file has to pad every stream to full 512-byte sectors, and the table stream is about 10 KB even when the document is empty. A DOCX file is packed with ZIP and has no such padding.

Size in bytes of the same file as DOC and as DOCX
File DOC to DOCX Smaller
empty 18,432 to 8,009 57%
text 25,088 to 8,634 66%
multi 18,432 to 8,406 54%
tableonly 19,968 to 8,189 59%
pic 57,344 to 47,138 18%
full 66,048 to 48,301 27%
big 768,000 to 54,519 93%

The gap is widest when the file has many repeated lines, like big.doc, because ZIP packs repeats well. It is narrowest when the file is mostly a picture, like pic.doc, because a PNG is already packed.

Which one should you keep?

Keep the DOC file if a program or a person needs it, like an old archive or a machine that opens only Word 2003 files. Otherwise save a DOCX copy, which Word and LibreOffice both open. Do not delete the DOC file until you have checked the DOCX copy against it.

Wrong page? If your file ends in .docx, read the guide to the DOCX format. It covers the newer format.

What Else Looks Like a DOC File? .dot, .wbk, .docx and endings that mislead

Not every file named .doc is a DOC file. We saved eight other kinds under the ending .doc. LibreOffice read six of them by their content, and the file command named all six. antiword and wvText read none.

The ending is a name that anyone can change. The Wikipedia entry shows the history, and the PRONOM record shows what a DOC file is: the container, the WordDocument stream and the text Word.Document.8. The table lists the endings that you may meet near .doc. We tested all but one.

Endings near the DOC file
Ending What it is Our test
.doc Word 97 to 2003 binary documents, the format in this guide Tested
.dot Word 97 to 2003 templates, says PRONOM and Microsoft Tested
.wbk Word backup, listed by PRONOM beside .doc Not tested
.docx Word 2007 and later, a ZIP file of XML Tested
.rtf Rich Text Format, readable text with markup Tested
.html A web page that Word can open Tested
.odt OpenDocument Text, also a ZIP file Tested
.xml Word 2003 XML documents Tested
.xls Excel workbooks, which start with the same 8 bytes Tested
.ppt PowerPoint slides, which start with the same 8 bytes Tested

Endings that mislead

We gave six other files the ending .doc. LibreOffice read all of them by content and returned all 52 items from every one. Neither antiword nor wvText returned anything from any of them. Catdoc and the text pass returned the text of the four plain text kinds, but not the two ZIP kinds.

What the renamed files showed
Kind First bytes
DOCX 50 4b 03 04
ODT 50 4b 03 04
RTF The text {\rtf1
HTML The text <!DOCTYP
XML The text <?xml
Text ef bb bf and the text

The two other compound files, our XLS and PPT, were named by the check script as not Word files. A program that trusts the ending would try to read them as Word documents. A program that reads the stream names would not.

Other Word and Office formats

For spreadsheets and slides with the same first bytes, see the guide to XLS workbooks and the guide to PPT slides. Outlook messages use a compound file too, and the MSG file guide covers them. For Word files in the newer format, see the guide to Word DOCX files.

Word binary files The .doc and .dot files in this guide. They contain a stream named WordDocument.
ZIP-based documents DOCX and ODT files. They start with 50 4b 03 04 and need an unzip step.
Text-based documents RTF, HTML, XML and text files. Readable text from the first bytes.
Not a Word file at all XLS, PPT and other compound files. They share the first 8 bytes but not the streams.

What Is the DOC File Format Made Of? The facts we could check, and what we left out

The DOC format is documented, but not completely. These are the facts we could check against Microsoft Learn, PRONOM, Wikipedia, FileInfo and our own 44 test DOC files, plus the points we left out.

Facts about the DOC file format
Part What we could check
Format Word 97 to 2003 binary format, called MS-DOC. Microsoft Learn lists revision 12.5 of the specification, dated February 17, 2026.
Container Compound File Binary, with 512-byte sectors in all our DOC files, a small stream cutoff of 4,096 bytes and a root CLSID of 00020906 for Word.
Word marker The stream WordDocument starts with wIdent 0xA5EC. nFib is one of five values, and ours was 0x0101.
Table stream The fWhichTblStm bit selects 1Table or 0Table. All our DOC files used 1Table.
Text Stored as 16-bit characters when the fCompressed bit is 0, and as 8-bit characters when it is 1, says Microsoft. LibreOffice wrote 16-bit text.
Pictures In the Data stream in our DOC files. We pulled out a PNG that matched the original byte for byte.
Encryption The fEncrypted bit marks encrypted or obfuscated files. Our password-protected file was decrypted by msoffcrypto-tool with the right password.
Properties In the SummaryInformation and DocumentSummaryInformation streams.
MIME type application/msword, says PRONOM
Apple type name com.microsoft.word.doc, says PRONOM

About the values we list

The positions and flag bits come from Microsoft Learn and from the files themselves. We checked them against files that five readers opened or refused in ways that matched. All of our DOC files came from LibreOffice 24.2.7 on Linux in October 2026. Word may write other values, so treat our numbers as guides, not promises.

The Wikipedia section on the specification says Microsoft released the DOC specification on February 15, 2008 under its Open Specification Promise, and that it does not cover all DOC features. So some tools still rely on reverse engineering. That fits what we saw: the tools disagreed on the same bad file.

What we left out

We did not test any DOC file made by Word. We also left out Fast Saved files, files with macros, Word 6 and 95 files and files with embedded objects. We did not use Word, Notepad, WordPad, Pages, Google Docs or WPS Office. Everything about them comes from Wikipedia, FileInfo and Microsoft.

The SysTools and Freeviewer tools come from their own pages, and we did not start either one. We name no prices. Their pages are not always consistent about free and paid features, so read the limits there.

Our damage tests are simple breaks in small files. We tried five readers, and others may behave differently. Our check script and repair script are research tools. Test them on copies before you trust them with anything that matters.

Sources checked

For the format and its history, see the Wikipedia article on DOC, the FileInfo page for the DOC ending and the PRONOM record fmt/40. For layout, see the MS-DOC specification, the FibBase page, the Fib page and the FcCompressed page. For damage and safety, see Microsoft on damaged documents, on blocked macros, on file block and on Document Inspector.

Every test count came from the 44 files and the scripts in our research folder.

Frequently Asked Questions About DOC Files

What is a DOC file?

DOC files are Word documents saved in the format that Microsoft used from Word 97 to Word 2003. Every DOC file is a small file system packed into one file, with the text, pictures and page settings in separate streams. FileInfo calls them word processing documents with formatted text, pictures, tables and print settings.

How do I open a DOC file?

Double-click it to open it in Word. Without Word, use LibreOffice, WPS Office, Apple Pages or Google Docs, which FileInfo lists for DOC files. In our tests, LibreOffice returned all the text from 6 of 7 good DOC files, more than antiword, wvText or catdoc.

How do I know if a file is a DOC file?

Look for a stream named WordDocument whose first two bytes are 0xA5EC. The first 8 bytes do not prove it, because DOC, XLS and PPT files all start with d0 cf 11 e0 a1 b1 1a e1. A short Python script on this page lists the streams and reads the Word header.

Is a DOC file safe to open?

Reading the text is low risk. Macros are the danger, because they can start code when you enable them. Microsoft says Office on Windows blocks macros in files from the internet by default. Do not enable content for a DOC file from someone you do not know.

How do I open a password-protected DOC file?

You need the password. In our test, LibreOffice, antiword, catdoc, wvText and a text pass all returned nothing from a protected file. With the right password, msoffcrypto-tool decrypted it, and the readers then returned all the text. We did not test any way to find a lost password.

Why will my DOC file not open?

The usual cause is a damaged container: a bad header, table or directory. In our 25 damaged files, a reader returned all the text from 12 as they were and from 14 after our repair script. A plain text pass found all of it in 20, so the words are often still inside.

How do I recover the text from a damaged DOC file?

Work on a copy. Try LibreOffice first, then a second reader. If both fail, pull the text out with a text pass, which found all the text in 20 of our 25 damaged files. Microsoft also lists Recover Text from Any File in Word, which keeps text and loses formatting.

Can I repair a DOC file with a script?

For some damage, yes. Our script fixed a wiped signature, a wrong wIdent and a table flag that points to a missing stream. It also fixed bytes in front, a text-mode transfer, a wrong sector size and a table entry that points to itself. Every fixed copy matched the original byte for byte. It cannot rebuild a wiped table.

How do I convert a DOC file to DOCX or PDF?

In Word, use Save As. With LibreOffice, use the command soffice --headless --convert-to docx report.doc, and change docx to pdf for a PDF. In our tests, all six outputs kept all 52 test items, and the picture came out byte for byte the same in DOCX and ODT.

What is the difference between DOC and DOCX?

DOC is the Word 97 to 2003 binary format in a compound file. DOCX is the format from Word 2007 on, a ZIP file of XML parts. In our seven pairs, the DOCX output was 18 to 93 percent smaller than the DOC file. A text pass reads DOC text but finds nothing in a DOCX file.

Why does my DOC file look like code or ask for a converter?

The ending may not match the file. We saved DOCX, ODT, RTF, HTML, XML and text files as .doc, and LibreOffice read them all by content. Look at the first bytes: 50 4b 03 04 means a ZIP-based file, and the text {\rtf1 means RTF.

Is there a free DOC viewer for Windows?

Freeviewer describes a Windows viewer that opens DOC files without Microsoft Office, and says it is free to use and also lists a paid option. SysTools describes a Windows tool for damaged Word files with a trial that only previews. We did not start either one. LibreOffice is free and read 6 of our 7 good files.

Still Stuck With a DOC File? Eight routes out, depending on what went wrong

Your DOC file will not open

Start with the damage grid. A wiped signature or a flag that points to a missing stream explains many cases, and small byte edits fix them.

Your DOC file asks for a password

Go to how to open a protected DOC file. You need the password, and the readers return nothing without it.

Does it end in .docx? The page on the newer DOCX format covers the newer Word format.

Is it an open-source document? See the guide to OpenDocument ODT files.

Is it a spreadsheet or slides? The Excel XLS page and the PowerPoint PPT page cover files that share the first 8 bytes.

Is it an Outlook message? The guide to Outlook MSG files explains messages saved from Outlook.

Do you want a fixed layout? The guide to PDF documents explains the format for documents that must look the same everywhere.

Is it a file type you do not know? Browse the file extension resource library, or send it to us on the submit a file type page.