public int processFile(Path file, boolean checkRootDir) throws IOException {
    if (verbose) {
      out.println("Scanning -> " + file);
    }

    if (checkRootDir) {
      Path rootPath = CommonFSUtils.getRootDir(getConf());
      String rootString = rootPath + Path.SEPARATOR;
      if (!file.toString().startsWith(rootString)) {
        // First we see if fully-qualified URI matches the root dir. It might
        // also be an absolute path in the same filesystem, so we prepend the FS
        // of the root dir and see if that fully-qualified URI matches.
        FileSystem rootFS = rootPath.getFileSystem(getConf());
        String qualifiedFile = rootFS.getUri().toString() + file.toString();
        if (!qualifiedFile.startsWith(rootString)) {
          err.println(
            "ERROR, file (" + file + ") is not in HBase's root directory (" + rootString + ")");
          return -2;
        }
      }
    }

    FileSystem fs = file.getFileSystem(getConf());
    if (!fs.exists(file)) {
      err.println("ERROR, file doesnt exist: " + file);
      return -2;
    }

    HFile.Reader reader = HFile.createReader(fs, file, CacheConfig.DISABLED, true, getConf());

    Map<byte[], byte[]> fileInfo = reader.getHFileInfo();

    KeyValueStatsCollector fileStats = null;

    if (verbose || printKey || checkRow || checkFamily || printStats || checkMobIntegrity) {
      // scan over file and read key/value's and check if requested
      HFileScanner scanner = reader.getScanner(getConf(), false, false, false);
      fileStats = new KeyValueStatsCollector();
      boolean shouldScanKeysValues;
      if (this.isSeekToRow && !Bytes.equals(row, reader.getFirstRowKey().orElse(null))) {
        // seek to the first kv on this row
        shouldScanKeysValues = (scanner.seekTo(PrivateCellUtil.createFirstOnRow(this.row)) != -1);
      } else {
        shouldScanKeysValues = scanner.seekTo();
      }
      if (shouldScanKeysValues) {
        scanKeysValues(file, fileStats, scanner, row);
      }
    }

    // print meta data
    if (shouldPrintMeta) {
      printMeta(reader, fileInfo);
    }

    if (printBlockIndex) {
      out.println("Block Index:");
      out.println(reader.getDataBlockIndexReader());
    }

    if (printBlockHeaders) {
      out.println("Block Headers:");
      /*
       * TODO: this same/similar block iteration logic is used in HFileBlock#blockRange and
       * TestLazyDataBlockDecompression. Refactor?
       */
      FSDataInputStreamWrapper fsdis = new FSDataInputStreamWrapper(fs, file);
      long fileSize = fs.getFileStatus(file).getLen();
      FixedFileTrailer trailer = FixedFileTrailer.readFromStream(fsdis.getStream(false), fileSize);
      long offset = trailer.getFirstDataBlockOffset(), max = trailer.getLastDataBlockOffset();
      HFileBlock block;
      while (offset <= max) {
        block = reader.readBlock(offset, -1, /* cacheBlock */ false, /* pread */ false,
          /* isCompaction */ false, /* updateCacheMetrics */ false, null, null);
        offset += block.getOnDiskSizeWithHeader();
        out.println(block);
      }
    }

    if (printStats) {
      fileStats.finish(printStatRanges);
      out.println("Stats:\n" + fileStats);
    }

    reader.close();
    return 0;
  }
Runs the command-line pretty-printer, and returns the desired command exit code (zero for
success, non-zero for failure).
hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFilePrettyPrinter.java