class FileReceiver extends TransmissionReceiver {
    /** Handler to notify when a file has been received. */
    private final Consumer<File> hnd;

    /** File to receive data into. */
    private File file;

    /** The corresponding file channel to work with. */
    @GridToStringExclude
    private FileIO fileIo;

    /**
     * @param meta Initial file meta info.
     * @param stopChecker Node stop or prcoess interrupt checker.
     * @param factory Factory to produce IO interface on files.
     * @param hnd Transmission handler provider to process download result.
     * @param path File path to destination receiver source.
     * @param log Ignite logger.
     */
    public FileReceiver(
        TransmissionMeta meta,
        int chunkSize,
        BooleanSupplier stopChecker,
        FileIOFactory factory,
        Consumer<File> hnd,
        String path,
        IgniteLogger log
    ) {
        super(meta, stopChecker, log, chunkSize);

        A.notNull(hnd, "FileHandler must be provided by transmission handler");
        A.notNull(path, "File absolute path cannot be null");
        A.ensure(!path.trim().isEmpty(), "File absolute path cannot be empty ");

        this.hnd = hnd;

        file = new File(path);

        try {
            fileIo = factory.create(file);

            fileIo.position(meta.offset());
        }
        catch (IOException e) {
            throw new IgniteException("Unable to open destination file. Receiver will be stopped: " +
                file.getAbsolutePath(), e);
        }
    }

    /** {@inheritDoc} */
    @Override public void receive(ReadableByteChannel ch) throws IOException, InterruptedException {
        super.receive(ch);

        if (transferred == meta.count())
            hnd.accept(file);
    }

    /** {@inheritDoc} */
    @Override protected void readChunk(ReadableByteChannel ch) throws IOException {<FILL_FUNCTION_BODY>}

    /** {@inheritDoc} */
    @Override public void close() {
        U.closeQuiet(fileIo);

        try {
            if (transferred != meta.count())
                Files.delete(file.toPath());
        }
        catch (IOException e) {
            U.error(log, "Error deleting not fully loaded file: " + file, e);
        }
    }

    /** {@inheritDoc} */
    @Override public String toString() {
        return S.toString(FileReceiver.class, this, "super", super.toString());
    }
}

        assert fileIo != null;

        long batchSize = Math.min(chunkSize, meta.count() - transferred);

        long read = fileIo.transferFrom(ch, meta.offset() + transferred, batchSize);

        if (read == 0)
            throw new IOException("Channel is reached the end of stream. Probably, channel is closed on the remote node");

        if (read > 0)
            transferred += read;
    
<methods>public void receive(java.nio.channels.ReadableByteChannel) throws java.io.IOException, java.lang.InterruptedException<variables>