cheat sheet
fc
Compare two text or binary files line-by-line or byte-by-byte and report their differences — the built-in Windows equivalent of Unix diff for quick file audits in cmd.exe.
fc — File Compare
What it is
fc (File Compare) is a built-in Windows command that compares two files and reports lines (or bytes) that differ between them. It works in two modes: ASCII mode for text files (default for .txt, .bat, and other text extensions) and binary mode (/B) for any file type. Use fc when you need a quick diff in a batch script or when you don't have a graphical diff tool installed. The PowerShell equivalent is Compare-Object; for richer diffs, use git diff or a dedicated tool.
Availability
fc ships as C:\Windows\System32\fc.exe on every Windows version.
fc /?
Output:
Compares two files or sets of files and displays the differences between them
FC [/A] [/B] [/C] [/L] [/LBn] [/N] [/OFF[LINE]] [/T] [/U] [/W] [/nnnn]
[drive1:][path1]filename1 [drive2:][path2]filename2
Syntax
fc [options] file1 file2
Output: (diff report or "no differences encountered")
Essential options
| Switch | Meaning |
|---|---|
/B | Binary comparison — byte by byte |
/C | Case-insensitive ASCII comparison |
/L | ASCII mode (default for text files) |
/N | Display line numbers in ASCII comparison |
/A | Abbreviate output — show only first and last differing line of each block |
/W | Compress whitespace (tabs and spaces treated as single space) |
/T | Do not expand tabs to spaces |
/U | Compare as Unicode (UTF-16 LE) text files |
/LBn | Set the internal line buffer to n lines (default 100); increase for large sync blocks |
/nnnn | Number of consecutive matching lines required to resync after a difference (default 2) |
Basic ASCII comparison
ASCII mode compares files line-by-line, reports blocks of differing lines, and prints the surrounding context markers. If the files are identical, fc prints a success message and exits with code 0.
fc old.txt new.txt
Output:
Comparing files old.txt and new.txt
***** old.txt
host=myhost
port=5432
***** new.txt
host=db.example.com
port=5432
*****
rem Identical files
fc base.txt base.txt
Output:
Comparing files base.txt and base.txt
FC: no differences encountered
Case-insensitive comparison (/C)
/C folds uppercase and lowercase when comparing lines, so ERROR and error are treated as identical.
fc /C expected.log actual.log
Output:
Comparing files expected.log and actual.log
FC: no differences encountered
Show line numbers (/N)
/N prepends the line number to each line in the diff report, making it easier to navigate to the difference in an editor.
fc /N config_v1.ini config_v2.ini
Output:
Comparing files config_v1.ini and config_v2.ini
***** config_v1.ini
12: timeout=30
13: retries=3
***** config_v2.ini
12: timeout=60
13: retries=5
*****
Binary comparison (/B)
/B compares files byte by byte and reports the offset and differing byte values in hexadecimal. Use it for executables, images, or any non-text file.
fc /B firmware_v1.bin firmware_v2.bin
Output:
Comparing files firmware_v1.bin and firmware_v2.bin
00000A20: 4F 47
00000A21: 52 68
00000B00: 00 01
Whitespace-insensitive comparison (/W)
/W collapses runs of spaces and tabs into a single space before comparing, so indentation differences do not count as changes.
fc /W formatted.sql minified.sql
Output:
Comparing files formatted.sql and minified.sql
FC: no differences encountered
Abbreviated output (/A)
/A suppresses middle lines in a differing block, showing only the first and last line of each changed section — useful when you want a high-level summary across a large file.
fc /A /N report_old.txt report_new.txt
Output:
Comparing files report_old.txt and report_new.txt
***** report_old.txt
3: Total records: 1024
...
47: Generated: 2026-04-27
***** report_new.txt
3: Total records: 1089
...
47: Generated: 2026-04-28
*****
Using fc in scripts (exit codes)
fc exits with code 0 when files match and code 1 when they differ, making it usable in batch conditionals to detect unexpected changes.
@echo off
fc /B expected_hash.bin actual_hash.bin > NUL
if errorlevel 1 (
echo MISMATCH: files differ.
exit /b 1
) else (
echo OK: files are identical.
)
Output:
OK: files are identical.
Common pitfalls
- ASCII mode for binary files produces garbage output — always use
/Bwhen comparing non-text files; without it,fctries to parse bytes as text lines. - Default resync window is 2 matching lines — if a block of changes is large and contains repeated content,
fcmay fail to resync and report the rest of the file as different; increase with/nnnn(e.g./5). - Line buffer limit is 100 lines — if a contiguous differing block exceeds 100 lines,
fcmay stop with "Resync Failed"; raise with/LB200or higher. - Exit code 1 means "differences found", not "error" — check
errorlevel 1with care; a true invocation error (bad path) also returns 1. fcis not a replacement forgit diff— it has no context lines, no unified diff format, and no ignore patterns; for code review, usegit diffor WinMerge.
Real-world recipes
Verify a downloaded file matches the original
@echo off
fc /B "C:\Downloads\setup.exe" "C:\Backups\setup.exe" > NUL
if errorlevel 1 (
echo WARNING: downloaded file differs from backup.
) else (
echo Checksum OK — files are byte-identical.
)
Output:
Checksum OK — files are byte-identical.
Diff two config snapshots and log the result
fc /N config_before.ini config_after.ini > C:\Logs\config_diff.txt
type C:\Logs\config_diff.txt
Output:
Comparing files config_before.ini and config_after.ini
***** config_before.ini
5: max_connections=50
***** config_after.ini
5: max_connections=100
*****
Check that a deployed file matches the source
fc /B "C:\Source\myapp.exe" "C:\Deploy\myapp.exe" > NUL
if not errorlevel 1 echo Deploy matches source.
Output:
Deploy matches source.
Comparison modes in depth
fc chooses ASCII or binary mode automatically based on file extension. Extensions associated with text content (.txt, .bat, .cmd, .ini, .log, .lst, .html, .htm, .asc, .c, .cpp, .h, .rc, .f, .for) trigger ASCII mode; anything else (including .exe, .dll, .bin, .zip, .jpg, .pdf) triggers binary mode. The /L and /B switches force the choice explicitly.
Forcing the wrong mode is the single most common source of confusing output:
rem Wrong: ASCII mode on a binary file produces "Resync Failed" or garbage
fc image.png image2.png
Output:
Comparing files image.png and image2.png
Resync Failed. Files are too different.
rem Right: explicit binary mode
fc /B image.png image2.png
Output:
Comparing files image.png and image2.png
000000B8: 4F 47
rem Wrong: binary mode on a text file reports every byte difference (incl. line endings)
fc /B old.txt new.txt
Output:
Comparing files old.txt and new.txt
00000010: 4F 49
00000011: 4C 4E
...
rem Right: ASCII mode for text — fc reports lines, not bytes
fc old.txt new.txt
Output: (line-based diff)
Resync algorithm
After detecting a differing line, fc enters a search phase to find the next set of matching lines in both files so output can rejoin sensibly. The resync window is controlled by /nnnn — the number of consecutive matching lines required to declare the files "back in sync". The default is 2.
rem Default — 2 matching lines required to resync
fc a.txt b.txt
Output (default):
Comparing files a.txt and b.txt
***** a.txt
line5
***** b.txt
line5-modified
*****
rem Require 5 matching lines (more conservative; better for noisy diffs)
fc /5 a.txt b.txt
Output:
(may report fewer differences if the 5-line window absorbs them)
rem Require only 1 matching line (aggressive resync; more diff blocks)
fc /1 a.txt b.txt
Output:
(produces more diff blocks because single matches count as resync)
If fc cannot find a resync within the line buffer (/LBn, default 100 lines), it gives up with:
Resync Failed. Files are too different.
This is not an error per se — it means the diff cannot be presented coherently. Increase /LB to allow larger differing blocks:
fc /LB500 longfile1.txt longfile2.txt
Output: (large diff)
Unicode comparison (/U)
/U instructs fc to read both files as UTF-16 LE (the encoding Windows calls "Unicode"). Without /U, fc treats UTF-16 files as binary because the alternating null bytes break ASCII parsing. UTF-8 files without a BOM read fine in ASCII mode; UTF-8 files with a BOM may emit a leading three-byte "garbage" line — strip the BOM first or compare with /B.
rem UTF-16 LE files (PowerShell `Out-File` default)
fc /U a.txt b.txt
Output:
Comparing files a.txt and b.txt
***** a.txt
hello
***** b.txt
hello world
*****
rem UTF-8 with BOM — strip BOM first for cleanest output
powershell -Command "(Get-Content a.txt -Raw) | Set-Content -Encoding utf8NoBOM a-clean.txt"
fc a-clean.txt b.txt
Output:
Comparing files a-clean.txt and b.txt
FC: no differences encountered
[!WARN] Mixing encodings between the two files causes
fcto report spurious differences. Either convert both files to the same encoding first, or use a tool that understands encodings (PowerShellCompare-Object,git diff).
Tab and whitespace handling (/T and /W)
By default fc expands tab characters into spaces at the next multiple of 8 columns before comparing. /T disables this expansion — tabs are compared as 0x09 bytes. /W collapses runs of whitespace (spaces and tabs) into a single space, useful when the only difference is indentation.
| Input A | Input B | Default | /T | /W |
|---|---|---|---|---|
foo\tbar | foo bar (8 spaces) | match | differ | match |
foo bar (3 spaces) | foo bar (1 space) | differ | differ | match |
\tfoo | foo | differ (leading tab → 8 spaces) | differ | match (whitespace stripped) |
rem Default: tab expansion, no whitespace collapse
fc indented.py reformatted.py
rem /T: tabs are bytes, not 8 spaces — useful for Makefile diffs
fc /T Makefile.old Makefile.new
rem /W: ignore indentation changes entirely
fc /W formatted.json minified.json
Output (fc /W):
Comparing files formatted.json and minified.json
FC: no differences encountered
Comparing sets of files
fc accepts wildcards in either filename position. With wildcards, fc compares each file in the source set against a same-named file in the destination set, producing a separate diff block per pair. Files present on only one side are reported as "FC: cannot open ... - No such file or directory".
rem Compare every .ini in two folders
fc C:\Config\*.ini C:\Backup\Config\*.ini
Output:
Comparing files C:\Config\app.ini and C:\BACKUP\CONFIG\app.ini
FC: no differences encountered
Comparing files C:\Config\db.ini and C:\BACKUP\CONFIG\db.ini
***** C:\Config\db.ini
port=5432
***** C:\BACKUP\CONFIG\db.ini
port=5433
*****
FC: cannot open C:\Config\new.ini - No such file or directory
fcdoes not recurse — wildcards only match files in the immediate directory. For recursive comparison, drive it from afor /rloop or switch to PowerShellCompare-Object.
Driving fc from a for loop
@echo off
for %f in (C:\Source\*.txt) do (
fc /N "%f" "D:\Dest\%~nxf" > NUL
if errorlevel 1 (
echo DIFF: %~nxf
)
)
Output:
DIFF: config.txt
DIFF: readme.txt
For recursion, use for /r:
@echo off
for /r C:\Source %f in (*.cs) do (
set "rel=%~pnxf"
fc /N "%f" "D:\Dest%~pnxf:C:\Source=%" > NUL 2>&1
if errorlevel 1 echo DIFF: %f
)
Output: (per-file diff indicators)
Exit codes
fc uses three exit codes; scripts that distinguish "differ" from "error" must inspect %ERRORLEVEL% carefully.
| Code | Meaning |
|---|---|
0 | Files identical |
1 | Files differ (or invocation error such as missing file) |
2 | Reserved (rarely seen) |
The conflation of "differ" and "missing file" in code 1 is the chief pitfall — wrap the call to detect missing inputs explicitly:
@echo off
if not exist a.txt ( echo Missing a.txt & exit /b 2 )
if not exist b.txt ( echo Missing b.txt & exit /b 2 )
fc a.txt b.txt > NUL
if errorlevel 1 ( echo DIFFER & exit /b 1 )
echo IDENTICAL
Output:
IDENTICAL
PowerShell equivalent: Compare-Object
Compare-Object is the modern PowerShell cmdlet for diffing collections — including line collections read from files. It produces structured PSCustomObject output with SideIndicator (<=, =>, ==) that piped commands can filter and format.
# Basic line-by-line diff
Compare-Object (Get-Content old.txt) (Get-Content new.txt)
Output:
InputObject SideIndicator
----------- -------------
port=5433 =>
port=5432 <=
# Case-insensitive comparison
Compare-Object (Get-Content a.txt) (Get-Content b.txt) -CaseSensitive:$false
Output: (lines that differ, ignoring case)
# Show unchanged lines too
Compare-Object (Get-Content a.txt) (Get-Content b.txt) -IncludeEqual
Output:
InputObject SideIndicator
----------- -------------
common-line ==
old-only <=
new-only =>
# Binary diff via byte arrays
Compare-Object `
([System.IO.File]::ReadAllBytes('a.bin')) `
([System.IO.File]::ReadAllBytes('b.bin'))
Output: (bytes that differ)
# Diff two directories by filename
Compare-Object `
(Get-ChildItem C:\Source -Recurse -File | Select-Object -ExpandProperty Name) `
(Get-ChildItem D:\Dest -Recurse -File | Select-Object -ExpandProperty Name)
Output:
InputObject SideIndicator
----------- -------------
new-file.txt <=
extra-file.log =>
Compare-Object vs fc
| Feature | fc | Compare-Object |
|---|---|---|
| Output format | Human-readable diff blocks | Structured PSObjects |
| Line numbers | /N | Add .ReadCount from Get-Content |
| Context lines | none | none (use git diff for context) |
| Whitespace handling | /W, /T | Manual via .Trim() or regex |
| Encoding awareness | /U only (UTF-16 LE) | Pass -Encoding to Get-Content |
| Recursive directory diff | no | yes (pipeline + -PassThru) |
| Binary diff | /B (byte offsets) | byte array comparison |
| Pipelinable | no | yes |
| Exit code | useful in cmd | use if on output count |
Use fc for quick interactive diffs in cmd.exe. Use Compare-Object when the diff result needs to drive further automation in PowerShell. For real source-code review, install git and use git diff --no-index a.txt b.txt, which provides unified diff format and context lines that neither built-in tool offers.
Comparing very large files
fc reads each file twice (once for content, once during resync), keeping a 100-line internal window by default. On multi-gigabyte files it is slow but does work; memory usage stays bounded.
For huge log files, prefer:
fc /LB10000 huge1.log huge2.log— increase resync buffer for large differing blocks.where /R . huge*.log+ hashes — if you only need "are they identical?", compute checksums instead:
certutil -hashfile huge1.log SHA256
certutil -hashfile huge2.log SHA256
Output:
SHA256 hash of huge1.log:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
CertUtil: -hashfile command completed successfully.
SHA256 hash of huge2.log:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
CertUtil: -hashfile command completed successfully.
If the hashes match, the files are identical — much faster than fc /B on large files.
# PowerShell — same idea
(Get-FileHash huge1.log -Algorithm SHA256).Hash -eq (Get-FileHash huge2.log -Algorithm SHA256).Hash
Output:
True
Output format reference
ASCII diffs follow this layout:
Comparing files A and B
***** A
<context line>
<differing line 1>
<differing line 2>
***** B
<context line>
<differing line 1'>
<differing line 2'>
*****
***** filenamemarks the start of a block from each file.*****(no name) closes the block.- With
/N, lines are prefixedNN: text. - With
/A, only the first and last differing line of each block are printed, separated by.... - Identical files produce a single line:
FC: no differences encountered.
Binary diffs use:
OFFSET: A-BYTE B-BYTE
The offset is a hex byte position from the start of file. Each difference is one line; there is no resync — fc /B always compares the entire file byte by byte.
fc and version control
fc is a poor fit for source-code review:
- No unified-diff format.
- No three-way merge.
- No context lines beyond the differing block itself.
- No file-rename detection.
- No
.gitignoreawareness. - ASCII mode does not understand multi-line strings or mixed line endings (CRLF vs LF triggers spurious differences unless you preprocess).
For any code-level diff, prefer:
git diff --no-index a.txt b.txt
Output (git diff):
diff --git a/a.txt b/b.txt
--- a/a.txt
+++ b/b.txt
@@ -3,3 +3,3 @@
host=myhost
-port=5432
+port=5433
user=alicedev
The unified format with context, +/- markers, and chunk headers is universally readable. fc remains useful for one-off non-source comparisons (config snapshots, build artefacts, downloaded binaries) where you don't want to involve git.
Common scenarios
Detect drift between dev and prod config
fc /N /C C:\Configs\dev\app.config C:\Configs\prod\app.config > C:\Logs\drift.txt
if errorlevel 1 (
echo Drift detected — see C:\Logs\drift.txt
)
Output:
Drift detected — see C:\Logs\drift.txt
Verify a network download
rem Compare downloaded installer against a known-good local copy
fc /B "C:\Downloads\setup.exe" "C:\KnownGood\setup.exe" > NUL
if errorlevel 1 (
echo Corrupt or different version
) else (
echo Verified.
)
Output:
Verified.
Compare two database export snapshots
fc /W /C export_2026-05-01.sql export_2026-05-15.sql > schema-diff.txt
type schema-diff.txt | findstr /N "CREATE\|ALTER\|DROP"
Output:
12:CREATE TABLE audit_log (
89:ALTER TABLE users ADD COLUMN last_login DATETIME;
Confirm a file matches expected content
@echo off
set EXPECTED=C:\Templates\readme-template.txt
set ACTUAL=C:\Projects\myapp\README.md
fc /W /C "%EXPECTED%" "%ACTUAL%" > NUL
if errorlevel 1 (
echo README has drifted from template
) else (
echo README matches template
)
Output: (depends on contents)
Sources
References consulted while writing this article. Links open in a new tab.
- Microsoft Learn — fc command reference — Authoritative flag list and parameter semantics used to build the Essential options table.
- SS64 — fc — Cross-version comparison and historical syntax notes.
Tips
Use
/Bwhenever you don't trust the file's extension. Forcing binary mode is harmless on text files (it shows byte-level diffs) but ASCII mode on binaries is a disaster.
For Unicode files (UTF-16 LE), always pass
/U. PowerShell's defaultOut-Filewrites UTF-16 — diffing those without/Uproduces unreadable output.
When
fcsays "Resync Failed", increase the line buffer with/LB500(or higher) before assuming the files really are too different.
For code review, install
gitand usegit diff --no-index a b— unified diff format with context is dramatically more useful thanfc's block format.
[!WARN] Exit code 1 means "differ OR error" — wrap with explicit
if existchecks before callingfcif your script must distinguish a real diff from a typo in the file path.