NumPy .npy / .npz Inspector
A .npy file is a very small header followed by a raw block of numbers, and that header is the only part this tool needs: six magic bytes, a version, a header length, and a Python dict literal — not JSON — carrying descr, fortran_order and shape. Because only the first kilobyte is read, a two-gigabyte array opens as fast as a two-kilobyte one, which is the whole point: you find out what is in a file before deciding whether it is worth loading. The descr is then decoded the way numpy would decode it. The leading character is the byte order — < little, > big, | not applicable — and a big-endian file is flagged, because reading it wrong does not look like an error: the numbers simply come out as other numbers. After that come the kind and the item size: b1 booleans, i1 to i8 and u1 to u8 integers, f2, f4 and f8 floats, c8 and c16 complex pairs, S<n> byte strings that keep interior NULs but lose trailing ones, U<n> text stored as UCS-4 so three characters occupy twelve bytes, M8 and m8 datetimes with their unit in brackets, V<n> raw void, and O — which means the array was written with allow_pickle=True and that loading it executes whatever was pickled, so it is flagged prominently rather than mentioned in passing. A structured dtype arrives as a list of (name, format) or (name, format, shape) tuples, possibly nested; the offsets are stored nowhere, they are the running sum of the item sizes, which is exactly why an aligned dtype carries unnamed padding fields in its own descr — those are shown too, with their spans. The counts are then arithmetic you can check: elements from the shape, expected bytes from elements times item size, and the bytes actually present after the header, so a file cut short by a failed copy or a full disk shows up as a shortfall rather than as a confident-looking header. The first values are decoded in the page for the plain numeric dtypes, in the order the elements sit in the file, so a Fortran-ordered array reads out column by column. A .npz is a zip of .npy members, listed with each member's dtype, shape and both sizes, and whether it was stored or deflated. What it will not do is unpickle anything, tell you what the numbers mean, or verify that the data is not garbage: it reports the file’s own claims and shows you where those claims disagree with its size.
How to use
- Drop a .npy or .npz onto the box. Only the header is read, so the size of the file does not matter.
- Read the dtype, shape and element count first — that is the answer to "what is in here", and it costs one read.
- Compare Data expected with Data present: less means the file is truncated, more means something was appended after the array.
- For a structured dtype open the field table, which gives each field its format, offset and size — including the unnamed padding an aligned dtype inserts.
- For a .npz, click a member name to inspect that array; the list shows what each member costs both inside the archive and unpacked.
Frequently asked questions
- What is actually in a .npy header?
- Six magic bytes (\x93NUMPY), a two-byte version, a header length, and then the header itself: a Python dict literal with exactly three keys — descr, fortran_order and shape. It is not JSON and JSON.parse cannot read it: the strings use single quotes, the booleans are True and False, the shape is a tuple written (3,) rather than (3), and there is a trailing comma before the closing brace. The literal is then padded with spaces so that the array data begins on a 64-byte boundary, which is what lets numpy memory-map the file with aligned loads. This tool shows the descr exactly as it is written in the file, so you can compare it with what numpy reports without wondering whether something was normalised on the way.
- Why is my string array four times bigger than the number of characters?
- Because numpy's U dtype stores UCS-4: every character is a fixed four bytes whatever it is, so the item size is four times the declared length. A U32 field costs 128 bytes per element even when every value is "ok". Byte strings (S) cost one byte per character but carry their own surprise: trailing NULs are stripped on read, so a value that genuinely ends in a zero byte cannot round-trip, while interior NULs are kept. If a dataset is unexpectedly huge, a U dtype is usually the reason — and the answer is normally to store text as S with an explicit encoding, or to keep the strings in a separate array altogether.
- The dtype says object. What does that mean, and why the warning?
- An object array does not store values at all, it stores pointers, so numpy serialises the whole thing with pickle when saving and un-pickles it when loading. Unpickling is not parsing: it can construct arbitrary objects and call arbitrary code, which is why numpy.load refuses object arrays unless you pass allow_pickle=True. A .npy whose descr is |O is therefore a program as much as it is data, and its safety is the safety of whoever wrote it. This page never unpickles anything — it reports the dtype and the size of the pickle and stops there. If the array holds ordinary strings or ragged lists, it is usually worth rewriting as a fixed-width dtype or as several arrays in a .npz.
- What does fortran_order actually change?
- Only the order in which the same numbers appear in the file. With fortran_order False the last axis varies fastest (C, row-major); with True the first axis does (column-major), which is what you get from np.asfortranarray or from data that came out of Fortran or MATLAB. The shape and the dtype are identical either way, so a reader that ignores the flag does not fail — it silently transposes your array, which is a much worse outcome than an exception. The preview here follows the file rather than the logical layout, so a Fortran-ordered 2×3 array reads out as column 0, then column 1, then column 2.
- Why are there three format versions?
- Version 1.0 keeps the header length in two bytes, which caps the header at 65535 bytes. Version 2.0 uses four bytes for the rare case where that is not enough — a structured dtype with a few thousand fields will do it, and the header can then be hundreds of kilobytes. Version 3.0 is 2.0 with the header declared UTF-8 instead of Latin-1, which numpy writes only when a field name contains a character Latin-1 cannot hold. numpy always picks the lowest version that fits, so a 2.0 or 3.0 file tells you something in itself. Worth knowing too: numpy's own loader refuses any header over 10000 bytes unless max_header_size is raised, so a legitimate 2.0 file can fail to load in Python while opening fine here.
- Does the file get uploaded, and can it open a very large array?
- No upload, and yes. The file is read through the browser’s File API and only in slices: the first kilobyte for the header, and a few kilobytes more for the value preview. A 2 GB array is never held in memory, which is precisely the case this exists for — someone hands you a file, you want its dtype and shape, and loading it would cost minutes and most of your RAM. For a .npz, only the zip directory at the end of the file and each member’s own header are read, so listing an archive is two reads plus one per member. Nothing is sent anywhere; you can disconnect from the network after the page loads and it still works.
Related tools
TAR Inspector
Open a .tar, .tar.gz or .tgz and list every entry — permissions, owner, size, timestamp and link target — without extracting it.
xz (.xz) Stream Inspector
Read an .xz container: stream header, every block header and filter chain, the index and the footer — with the true uncompressed size, unpacking nothing.
gzip (.gz) Inspector
Read a .gz header field by field, walk every member, and verify the trailer by recomputing CRC32 and the real size in your browser.
SQLite Database Inspector
Open a .sqlite or .db file in your browser and read its structure: page size, encoding, journal mode, and every table with its real row count.
Static Library (.a) Inspector
Read a .a archive in the browser: members with sizes and dates, the symbols each object defines and needs, and whether the symbol index has gone stale.
CSV Viewer & Sorter
View CSV / TSV data as a sortable, searchable table — open a file or paste rows, no spreadsheet required.