MINIFICPP-1319 - Stream refactor

Signed-off-by: Arpad Boda <aboda@apache.org>

This closes #864
diff --git a/controller/Controller.h b/controller/Controller.h
index 726d3b6..ca4a634 100644
--- a/controller/Controller.h
+++ b/controller/Controller.h
@@ -32,10 +32,10 @@
 bool sendSingleCommand(std::unique_ptr<minifi::io::Socket> socket, uint8_t op, const std::string value) {
   socket->initialize();
   std::vector<uint8_t> data;
-  minifi::io::BaseStream stream;
-  stream.writeData(&op, 1);
-  stream.writeUTF(value);
-  return socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) == stream.getSize();
+  minifi::io::BufferStream stream;
+  stream.write(&op, 1);
+  stream.write(value);
+  return socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) == stream.size();
 }
 
 /**
@@ -72,23 +72,23 @@
   socket->initialize();
   std::vector<uint8_t> data;
   uint8_t op = minifi::c2::Operation::UPDATE;
-  minifi::io::BaseStream stream;
-  stream.writeData(&op, 1);
-  stream.writeUTF("flow");
-  stream.writeUTF(file);
-  if (socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) < 0) {
+  minifi::io::BufferStream stream;
+  stream.write(&op, 1);
+  stream.write("flow");
+  stream.write(file);
+  if (socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) < 0) {
     return -1;
   }
   // read the response
   uint8_t resp = 0;
-  socket->readData(&resp, 1);
+  socket->read(&resp, 1);
   if (resp == minifi::c2::Operation::DESCRIBE) {
     uint16_t connections = 0;
     socket->read(connections);
     out << connections << " are full" << std::endl;
     for (int i = 0; i < connections; i++) {
       std::string fullcomponent;
-      socket->readUTF(fullcomponent);
+      socket->read(fullcomponent);
       out << fullcomponent << " is full" << std::endl;
     }
   }
@@ -103,22 +103,22 @@
   socket->initialize();
   std::vector<uint8_t> data;
   uint8_t op = minifi::c2::Operation::DESCRIBE;
-  minifi::io::BaseStream stream;
-  stream.writeData(&op, 1);
-  stream.writeUTF("getfull");
-  if (socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) < 0) {
+  minifi::io::BufferStream stream;
+  stream.write(&op, 1);
+  stream.write("getfull");
+  if (socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) < 0) {
     return -1;
   }
   // read the response
   uint8_t resp = 0;
-  socket->readData(&resp, 1);
+  socket->read(&resp, 1);
   if (resp == minifi::c2::Operation::DESCRIBE) {
     uint16_t connections = 0;
     socket->read(connections);
     out << connections << " are full" << std::endl;
     for (int i = 0; i < connections; i++) {
       std::string fullcomponent;
-      socket->readUTF(fullcomponent);
+      socket->read(fullcomponent);
       out << fullcomponent << " is full" << std::endl;
     }
   }
@@ -129,15 +129,15 @@
   socket->initialize();
   std::vector<uint8_t> data;
   uint8_t op = minifi::c2::Operation::DESCRIBE;
-  minifi::io::BaseStream stream;
-  stream.writeData(&op, 1);
-  stream.writeUTF("jstack");
-  if (socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) < 0) {
+  minifi::io::BufferStream stream;
+  stream.write(&op, 1);
+  stream.write("jstack");
+  if (socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) < 0) {
     return -1;
   }
   // read the response
   uint8_t resp = 0;
-  socket->readData(&resp, 1);
+  socket->read(&resp, 1);
   if (resp == minifi::c2::Operation::DESCRIBE) {
 
     uint64_t size = 0;
@@ -146,11 +146,11 @@
     for (int i = 0; i < size; i++) {
       std::string name;
       uint64_t lines;
-      socket->readUTF(name);
+      socket->read(name);
       socket->read(lines);
       for (int j = 0; j < lines; j++) {
         std::string line;
-        socket->readUTF(line);
+        socket->read(line);
         out << name << " -- " << line << std::endl;
       }
 
@@ -168,19 +168,19 @@
   socket->initialize();
   std::vector<uint8_t> data;
   uint8_t op = minifi::c2::Operation::DESCRIBE;
-  minifi::io::BaseStream stream;
-  stream.writeData(&op, 1);
-  stream.writeUTF("queue");
-  stream.writeUTF(connection);
-  if (socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) < 0) {
+  minifi::io::BufferStream stream;
+  stream.write(&op, 1);
+  stream.write("queue");
+  stream.write(connection);
+  if (socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) < 0) {
     return -1;
   }
   // read the response
   uint8_t resp = 0;
-  socket->readData(&resp, 1);
+  socket->read(&resp, 1);
   if (resp == minifi::c2::Operation::DESCRIBE) {
     std::string size;
-    socket->readUTF(size);
+    socket->read(size);
     out << "Size/Max of " << connection << " " << size << std::endl;
   }
   return 0;
@@ -188,23 +188,23 @@
 
 int listComponents(std::unique_ptr<minifi::io::Socket> socket, std::ostream &out, bool show_header = true) {
   socket->initialize();
-  minifi::io::BaseStream stream;
+  minifi::io::BufferStream stream;
   uint8_t op = minifi::c2::Operation::DESCRIBE;
-  stream.writeData(&op, 1);
-  stream.writeUTF("components");
-  if (socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) < 0) {
+  stream.write(&op, 1);
+  stream.write("components");
+  if (socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) < 0) {
     return -1;
   }
   uint16_t responses = 0;
-  socket->readData(&op, 1);
+  socket->read(&op, 1);
   socket->read(responses);
   if (show_header)
     out << "Components:" << std::endl;
 
   for (int i = 0; i < responses; i++) {
     std::string name, status;
-    socket->readUTF(name, false);
-    socket->readUTF(status, false);
+    socket->read(name, false);
+    socket->read(status, false);
     out << name << ", running: " << status << std::endl;
   }
   return 0;
@@ -212,22 +212,22 @@
 
 int listConnections(std::unique_ptr<minifi::io::Socket> socket, std::ostream &out, bool show_header = true) {
   socket->initialize();
-  minifi::io::BaseStream stream;
+  minifi::io::BufferStream stream;
   uint8_t op = minifi::c2::Operation::DESCRIBE;
-  stream.writeData(&op, 1);
-  stream.writeUTF("connections");
-  if (socket->writeData(const_cast<uint8_t*>(stream.getBuffer()), stream.getSize()) < 0) {
+  stream.write(&op, 1);
+  stream.write("connections");
+  if (socket->write(const_cast<uint8_t*>(stream.getBuffer()), stream.size()) < 0) {
     return -1;
   }
   uint16_t responses = 0;
-  socket->readData(&op, 1);
+  socket->read(&op, 1);
   socket->read(responses);
   if (show_header)
     out << "Connection Names:" << std::endl;
 
   for (int i = 0; i < responses; i++) {
     std::string name;
-    socket->readUTF(name, false);
+    socket->read(name, false);
     out << name << std::endl;
   }
   return 0;
diff --git a/extensions/bustache/ApplyTemplate.cpp b/extensions/bustache/ApplyTemplate.cpp
index 5dad2bb..72f7d2e 100644
--- a/extensions/bustache/ApplyTemplate.cpp
+++ b/extensions/bustache/ApplyTemplate.cpp
@@ -82,7 +82,7 @@
 
   // TODO(calebj) write ostream reciever for format() to prevent excessive copying
   std::string ostring = to_string(format(data));
-  stream->writeData(reinterpret_cast<uint8_t *>(const_cast<char *>(ostring.c_str())),
+  stream->write(reinterpret_cast<uint8_t *>(const_cast<char *>(ostring.c_str())),
                     ostring.length());
 
   return ostring.length();
diff --git a/extensions/civetweb/processors/ListenHTTP.h b/extensions/civetweb/processors/ListenHTTP.h
index ce9601e..cdffa5f 100644
--- a/extensions/civetweb/processors/ListenHTTP.h
+++ b/extensions/civetweb/processors/ListenHTTP.h
@@ -137,11 +137,11 @@
         : out_str_(out_str) {
     }
     int64_t process(std::shared_ptr<io::BaseStream> stream) {
-      out_str_->resize(stream->getSize());
-      uint64_t num_read = stream->readData(reinterpret_cast<uint8_t *>(&(*out_str_)[0]),
-                                           gsl::narrow<int>(stream->getSize()));
+      out_str_->resize(stream->size());
+      uint64_t num_read = stream->read(reinterpret_cast<uint8_t *>(&(*out_str_)[0]),
+                                           gsl::narrow<int>(stream->size()));
 
-      if (num_read != stream->getSize()) {
+      if (num_read != stream->size()) {
         throw std::runtime_error("GraphReadCallback failed to fully read flow file input stream");
       }
 
diff --git a/extensions/coap/protocols/CoapC2Protocol.cpp b/extensions/coap/protocols/CoapC2Protocol.cpp
index f51d5a3..805f78c 100644
--- a/extensions/coap/protocols/CoapC2Protocol.cpp
+++ b/extensions/coap/protocols/CoapC2Protocol.cpp
@@ -58,7 +58,7 @@
 int CoapProtocol::writeAcknowledgement(io::BaseStream *stream, const minifi::c2::C2Payload &payload) {
   auto ident = payload.getIdentifier();
   auto state = payload.getStatus().getState();
-  stream->writeUTF(ident);
+  stream->write(ident);
   uint8_t payloadState = 0;
   switch (state) {
     case state::UpdateState::NESTED:
@@ -93,14 +93,14 @@
 
     const std::string agentIdent = minifi::c2::PayloadParser::getInstance(payload).in("agentInfo").getAs<std::string>("identifier");
 
-    stream->writeUTF(deviceIdent, false);
+    stream->write(deviceIdent, false);
 
     logger_->log_trace("Writing heartbeat with device Ident %s and agent Ident %s", deviceIdent, agentIdent);
 
     if (agentIdent.empty()) {
       return -1;
     }
-    stream->writeUTF(agentIdent, false);
+    stream->write(agentIdent, false);
 
     try {
       auto flowInfoParser = minifi::c2::PayloadParser::getInstance(payload).in("flowInfo");
@@ -115,7 +115,7 @@
       componentParser.foreach([this, stream](const minifi::c2::C2Payload &component) {
         auto myParser = minifi::c2::PayloadParser::getInstance(component);
         bool running = false;
-        stream->writeUTF(component.getLabel());
+        stream->write(component.getLabel());
         try {
           running = myParser.getAs<bool>("running");
         }
@@ -128,7 +128,7 @@
       stream->write(size);
       queueParser.foreach([this, stream](const minifi::c2::C2Payload &component) {
         auto myParser = minifi::c2::PayloadParser::getInstance(component);
-        stream->writeUTF(component.getLabel());
+        stream->write(component.getLabel());
         uint64_t datasize = 0, datasizemax = 0, qsize = 0, sizemax = 0;
         try {
           datasize = myParser.getAs<uint64_t>("dataSize");
@@ -148,8 +148,8 @@
       auto bucketId = vfsParser.getAs<std::string>("bucketId");
       auto flowId = vfsParser.getAs<std::string>("flowId");
 
-      stream->writeUTF(bucketId);
-      stream->writeUTF(flowId);
+      stream->write(bucketId);
+      stream->write(flowId);
 
     } catch (const minifi::c2::PayloadParseException &pe) {
       logger_->log_error("Parser exception occurred, but is ignorable, reason %s", pe.what());
@@ -212,7 +212,7 @@
   uint8_t payload_type = 0;
   uint64_t payload_u64 = 0;
   uint16_t size = 0;
-  io::BaseStream stream;
+  io::BufferStream stream;
 
   stream.write(version);
   std::string endpoint = "heartbeat";
@@ -238,7 +238,7 @@
       return minifi::c2::C2Payload(payload.getOperation(), state::UpdateState::READ_ERROR, true);
   };
 
-  size_t bsize = stream.getSize();
+  size_t bsize = stream.size();
 
   CoapMessage msg;
   msg.data_ = const_cast<uint8_t *>(stream.getBuffer());
@@ -249,8 +249,7 @@
   if (isRegistrationMessage(message)) {
     require_registration_ = true;
   } else if (message.getSize() > 0) {
-    io::DataStream byteStream(message.getData(), message.getSize());
-    io::BaseStream responseStream(&byteStream);
+    io::BufferStream responseStream(message.getData(), message.getSize());
     responseStream.read(version);
     responseStream.read(size);
     logger_->log_trace("Received ack. version %d. number of operations %d", version, size);
@@ -261,8 +260,8 @@
       uint16_t argsize = 0;
       std::string operand, id;
       REQUIRE_SIZE_IF(1, responseStream.read(operationType))
-      REQUIRE_VALID(responseStream.readUTF(id, false))
-      REQUIRE_VALID(responseStream.readUTF(operand, false))
+      REQUIRE_VALID(responseStream.read(id, false))
+      REQUIRE_VALID(responseStream.read(operand, false))
 
       logger_->log_trace("Received op %d, with id %s and operand %s", operationType, id, operand);
       auto newOp = getOperation(operationType);
@@ -277,8 +276,8 @@
       responseStream.read(argsize);
       for (int j = 0; j < argsize; j++) {
         std::string key, value;
-        REQUIRE_VALID(responseStream.readUTF(key))
-        REQUIRE_VALID(responseStream.readUTF(value))
+        REQUIRE_VALID(responseStream.read(key))
+        REQUIRE_VALID(responseStream.read(value))
         new_command.operation_arguments[key] = value;
       }
 
diff --git a/extensions/coap/server/CoapServer.h b/extensions/coap/server/CoapServer.h
index 8c52190..b5bad6b 100644
--- a/extensions/coap/server/CoapServer.h
+++ b/extensions/coap/server/CoapServer.h
@@ -65,7 +65,7 @@
 class CoapResponse {
   friend class CoapQuery;
  public:
-  CoapResponse(int code, std::unique_ptr<uint8_t> data, size_t size)
+  CoapResponse(int code, std::unique_ptr<uint8_t[]> data, size_t size)
       : code_(code),
         data_(std::move(data)),
         size_(size) {
@@ -88,7 +88,7 @@
   CoapResponse &operator=(CoapResponse &&qry) = default;
  private:
   int code_;
-  std::unique_ptr<uint8_t> data_;
+  std::unique_ptr<uint8_t[]> data_;
   size_t size_;
 };
 
diff --git a/extensions/coap/tests/CoapC2VerifyHeartbeat.cpp b/extensions/coap/tests/CoapC2VerifyHeartbeat.cpp
index f0e3797..2402ffa 100644
--- a/extensions/coap/tests/CoapC2VerifyHeartbeat.cpp
+++ b/extensions/coap/tests/CoapC2VerifyHeartbeat.cpp
@@ -118,32 +118,32 @@
 
     {
       // valid response version 3, 0 ops
-      uint8_t *data = new uint8_t[5] { 0x00, 0x03, 0x00, 0x01, 0x00 };
-      minifi::coap::CoapResponse response(205, std::unique_ptr<uint8_t>(data), 5);
+      auto data = std::unique_ptr<uint8_t[]>(new uint8_t[5] { 0x00, 0x03, 0x00, 0x01, 0x00 });
+      minifi::coap::CoapResponse response(205, std::move(data), 5);
       responses.enqueue(std::move(response));
     }
 
     {
       // valid response
-      uint8_t *data = new uint8_t[5] { 0x00, 0x03, 0x00, 0x00, 0x00 };
-      minifi::coap::CoapResponse response(205, std::unique_ptr<uint8_t>(data), 5);
+      auto data = std::unique_ptr<uint8_t[]>(new uint8_t[5] { 0x00, 0x03, 0x00, 0x00, 0x00 });
+      minifi::coap::CoapResponse response(205, std::move(data), 5);
       responses.enqueue(std::move(response));
     }
 
     {
       // should result in valid operation
-      minifi::io::BaseStream stream;
+      minifi::io::BufferStream stream;
       uint16_t version = 0, size = 1;
       uint8_t operation = 1;
       stream.write(version);
       stream.write(size);
       stream.write(&operation, 1);
-      stream.writeUTF("id");
-      stream.writeUTF("operand");
+      stream.write("id");
+      stream.write("operand");
 
-      uint8_t *data = new uint8_t[stream.getSize()];
-      memcpy(data, stream.getBuffer(), stream.getSize());
-      minifi::coap::CoapResponse response(205, std::unique_ptr<uint8_t>(data), stream.getSize());
+      auto data = std::unique_ptr<uint8_t[]>(new uint8_t[stream.size()]);
+      memcpy(data.get(), stream.getBuffer(), stream.size());
+      minifi::coap::CoapResponse response(205, std::move(data), stream.size());
       responses.enqueue(std::move(response));
     }
 
diff --git a/extensions/http-curl/client/HTTPCallback.h b/extensions/http-curl/client/HTTPCallback.h
index b124bc6..5415979 100644
--- a/extensions/http-curl/client/HTTPCallback.h
+++ b/extensions/http-curl/client/HTTPCallback.h
@@ -81,9 +81,9 @@
   int64_t process(std::shared_ptr<io::BaseStream> stream) override {
     std::vector<char> vec;
 
-    if (stream->getSize() > 0) {
-      vec.resize(stream->getSize());
-      stream->readData(reinterpret_cast<uint8_t*>(vec.data()), gsl::narrow<int>(stream->getSize()));
+    if (stream->size() > 0) {
+      vec.resize(stream->size());
+      stream->read(reinterpret_cast<uint8_t*>(vec.data()), gsl::narrow<int>(stream->size()));
     }
 
     return processInner(std::move(vec));
diff --git a/extensions/http-curl/client/HTTPStream.cpp b/extensions/http-curl/client/HTTPStream.cpp
index e3cc31f..be01261 100644
--- a/extensions/http-curl/client/HTTPStream.cpp
+++ b/extensions/http-curl/client/HTTPStream.cpp
@@ -26,7 +26,6 @@
 
 #include "HTTPCallback.h"
 #include "io/validation.h"
-#include "io/NonConvertingStream.h"
 namespace org {
 namespace apache {
 namespace nifi {
@@ -44,7 +43,7 @@
   // submit early on
 }
 
-void HttpStream::closeStream() {
+void HttpStream::close() {
   http_callback_.close();
   http_read_callback_.close();
 }
@@ -54,20 +53,10 @@
   throw std::exception();
 }
 
-int HttpStream::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    return -1;
-  }
-  return writeData(buf.data(), buflen);
-}
-
 // data stream overrides
 
-int HttpStream::writeData(uint8_t *value, int size) {
+int HttpStream::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
   if (!IsNullOrEmpty(value)) {
     if (!started_) {
       std::lock_guard<std::mutex> lock(mutex_);
@@ -86,29 +75,8 @@
   }
 }
 
-template<typename T>
-inline int HttpStream::readBuffer(std::vector<uint8_t>& buf, const T& t) {
-  buf.resize(sizeof t);
-  return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-}
-
-int HttpStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int ret = readData(buf.data(), buflen);
-
-  if (ret < buflen) {
-    buf.resize((std::max)(ret, 0));
-  }
-  return ret;
-}
-
-int HttpStream::readData(uint8_t *buf, int buflen) {
+int HttpStream::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   if (!IsNullOrEmpty(buf)) {
     if (!started_) {
       std::lock_guard<std::mutex> lock(mutex_);
diff --git a/extensions/http-curl/client/HTTPStream.h b/extensions/http-curl/client/HTTPStream.h
index 9ca4821..b39e8b6 100644
--- a/extensions/http-curl/client/HTTPStream.h
+++ b/extensions/http-curl/client/HTTPStream.h
@@ -46,7 +46,7 @@
     forceClose();
   }
 
-  virtual void closeStream() override;
+  virtual void close() override;
 
   const std::shared_ptr<utils::HTTPClient> &getClientRef() {
     return http_client_;
@@ -62,7 +62,7 @@
       // lock shouldn't be needed here as call paths currently guarantee
       // flow, but we should be safe anyway.
       std::lock_guard<std::mutex> lock(mutex_);
-      closeStream();
+      close();
       http_client_->forceClose();
       if (http_client_future_.valid()) {
         http_client_future_.get();
@@ -77,48 +77,28 @@
    * Skip to the specified offset.
    * @param offset offset to which we will skip
    */
-  virtual void seek(uint64_t offset) override;
+  void seek(uint64_t offset) override;
 
-  const size_t getSize() const override {
+  size_t size() const override {
     return written;
   }
 
-  // data stream extensions
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  virtual int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  virtual int readData(uint8_t *buf, int buflen) override;
+  using BaseStream::write;
+  using BaseStream::read;
 
   /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
+   * Reads data and places it into buf
+   * @param buf buffer in which we extract data
+   * @param buflen
    */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * writes value to stream
    * @param value value to write
    * @param size size of value
    */
-  virtual int writeData(uint8_t *value, int size) override;
-
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   **/
-  const uint8_t *getBuffer() const {
-    throw std::runtime_error("Stream does not support this operation");
-  }
+  int write(const uint8_t *value, int size) override;
 
   static bool submit_client(std::shared_ptr<utils::HTTPClient> client) {
     if (client == nullptr)
diff --git a/extensions/http-curl/processors/InvokeHTTP.cpp b/extensions/http-curl/processors/InvokeHTTP.cpp
index 5a6dc6b..6901537 100644
--- a/extensions/http-curl/processors/InvokeHTTP.cpp
+++ b/extensions/http-curl/processors/InvokeHTTP.cpp
@@ -42,7 +42,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
@@ -384,7 +384,7 @@
         response_flow->addAttribute(STATUS_MESSAGE, response_headers.at(0));
       response_flow->addAttribute(REQUEST_URL, url);
       response_flow->addAttribute(TRANSACTION_ID, tx_id);
-      io::DataStream stream((const uint8_t*) response_body.data(), response_body.size());
+      io::BufferStream stream((const uint8_t*) response_body.data(), response_body.size());
       // need an import from the data stream.
       session->importFrom(stream, response_flow);
     }
diff --git a/extensions/http-curl/sitetosite/HTTPProtocol.cpp b/extensions/http-curl/sitetosite/HTTPProtocol.cpp
index bb60011..9361e5e 100644
--- a/extensions/http-curl/sitetosite/HTTPProtocol.cpp
+++ b/extensions/http-curl/sitetosite/HTTPProtocol.cpp
@@ -72,8 +72,8 @@
       if (IsNullOrEmpty(url)) {
         logger_->log_debug("Location is empty");
       } else {
-        org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> crcstream(peer_.get());
-        auto transaction = std::make_shared<HttpTransaction>(direction, crcstream);
+        org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> crcstream(gsl::make_not_null(peer_.get()));
+        auto transaction = std::make_shared<HttpTransaction>(direction, std::move(crcstream));
         transaction->initialize(this, url);
         auto transactionId = parseTransactionId(url);
         if (IsNullOrEmpty(transactionId))
@@ -89,7 +89,7 @@
         }
 
         client->appendHeader(PROTOCOL_VERSION_HEADER, "1");
-        peer_->setStream(std::unique_ptr<io::DataStream>(new io::HttpStream(client)));
+        peer_->setStream(std::unique_ptr<io::BaseStream>(new io::HttpStream(client)));
         transactionID = transaction->getUUIDStr();
         logger_->log_debug("Created transaction id -%s-", transactionID);
         known_transactions_[transaction->getUUIDStr()] = transaction;
@@ -110,7 +110,7 @@
 
     if (transaction->getDirection() == SEND) {
       auto stream = dynamic_cast<io::HttpStream*>(peer_->getStream());
-      stream->closeStream();
+      stream->close();
       auto client = stream->getClient();
       if (client->getResponseCode() == 202) {
         code = CONFIRM_TRANSACTION;
diff --git a/extensions/http-curl/sitetosite/HTTPTransaction.h b/extensions/http-curl/sitetosite/HTTPTransaction.h
index 6fa25ed..0390d93 100644
--- a/extensions/http-curl/sitetosite/HTTPTransaction.h
+++ b/extensions/http-curl/sitetosite/HTTPTransaction.h
@@ -36,8 +36,8 @@
  */
 class HttpTransaction : public sitetosite::Transaction {
  public:
-  explicit HttpTransaction(sitetosite::TransferDirection direction, org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> &stream)
-      : Transaction(direction, stream),
+  explicit HttpTransaction(sitetosite::TransferDirection direction, org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> &&stream)
+      : Transaction(direction, std::move(stream)),
         client_ref_(nullptr) {
   }
 
diff --git a/extensions/http-curl/tests/CivetStream.h b/extensions/http-curl/tests/CivetStream.h
index fb33eec..e04f36c 100644
--- a/extensions/http-curl/tests/CivetStream.h
+++ b/extensions/http-curl/tests/CivetStream.h
@@ -33,92 +33,26 @@
 namespace minifi {
 namespace io {
 
-class CivetStream : public io::BaseStream {
+class CivetStream : public io::InputStream {
  public:
   /**
    * File Stream constructor that accepts an fstream shared pointer.
    * It must already be initialized for read and write.
    */
-  explicit CivetStream(struct mg_connection *conn)
-      : io::BaseStream(), conn(conn) {
-
-  }
+  explicit CivetStream(struct mg_connection *conn) : conn(conn) {}
 
   ~CivetStream() override = default;
-  /**
-   * Skip to the specified offset.
-   * @param offset offset to which we will skip
-   */
-  void seek(uint64_t offset) override { }
-
-  const size_t getSize() const override {
-    return BaseStream::readBuffer;
-  }
-
-  // data stream extensions
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(std::vector<uint8_t> &buf, int buflen) override {
-    if (buflen < 0) {
-      throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-    }
-
-    if (buf.size() < gsl::narrow<size_t>(buflen)) {
-      buf.resize(buflen);
-    }
-    int ret = readData(buf.data(), buflen);
-
-    if (ret < buflen) {
-      buf.resize((std::max)(ret, 0));
-    }
-    return ret;
-  }
 
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    */
-  int readData(uint8_t *buf, int buflen) override {
-    return mg_read(conn,buf,buflen);
-  }
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen) {
-    return 0;
-  }
-
-  /**
-   * writes value to stream
-   * @param value value to write
-   * @param size size of value
-   */
-  int writeData(uint8_t *value, int size) override {
-    return 0;
+  int read(uint8_t *buf, int buflen) override {
+    return mg_read(conn, buf, buflen);
   }
 
  protected:
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read
-   */
-  template<typename T>
-  inline int readBuffer(std::vector<uint8_t>& buf, const T& t) {
-    buf.resize(sizeof t);
-    return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-  }
-
   struct mg_connection *conn;
 
  private:
diff --git a/extensions/http-curl/tests/HTTPHandlers.h b/extensions/http-curl/tests/HTTPHandlers.h
index 4583f8c..416d775 100644
--- a/extensions/http-curl/tests/HTTPHandlers.h
+++ b/extensions/http-curl/tests/HTTPHandlers.h
@@ -209,7 +209,7 @@
 
     if (!wrong_uri) {
       minifi::io::CivetStream civet_stream(conn);
-      minifi::io::CRCStream < minifi::io::CivetStream > stream(&civet_stream);
+      minifi::io::CRCStream < minifi::io::CivetStream > stream(gsl::make_not_null(&civet_stream));
       uint32_t num_attributes;
       int read;
       uint64_t total_size = 0;
@@ -221,10 +221,10 @@
 
       for (uint32_t i = 0; i < num_attributes; i++) {
         std::string name, value;
-        read = stream.readUTF(name, true);
+        read = stream.read(name, true);
         if(!isServerRunning())return false;
         assert(read > 0); total_size += read;
-        read = stream.readUTF(value, true);
+        read = stream.read(value, true);
         if(!isServerRunning())return false;
         assert(read > 0); total_size += read;
         flow->attributes[name] = value;
@@ -238,7 +238,7 @@
       flow->data.resize(gsl::narrow<size_t>(length));
       flow->total_size = total_size;
 
-      read = stream.readData(flow->data.data(), gsl::narrow<int>(length));
+      read = stream.read(flow->data.data(), gsl::narrow<int>(length));
       if(!isServerRunning())return false;
       assert(read == length);
 
@@ -280,18 +280,18 @@
           "Content-Type: application/octet-stream\r\n"
           "Connection: close\r\n\r\n",
           total);
-      minifi::io::BaseStream serializer;
-      minifi::io::CRCStream < minifi::io::BaseStream > stream(&serializer);
+      minifi::io::BufferStream serializer;
+      minifi::io::CRCStream < minifi::io::BaseStream > stream(gsl::make_not_null(&serializer));
       for (const auto& flow : flows) {
         uint32_t num_attributes = flow->attributes.size();
         stream.write(num_attributes);
         for (const auto& entry : flow->attributes) {
-          stream.writeUTF(entry.first);
-          stream.writeUTF(entry.second);
+          stream.write(entry.first);
+          stream.write(entry.second);
         }
         uint64_t length = flow->data.size();
         stream.write(length);
-        stream.writeData(flow->data.data(), gsl::narrow<int>(length));
+        stream.write(flow->data.data(), gsl::narrow<int>(length));
       }
     } else {
       mg_printf(conn, "HTTP/1.1 200 OK\r\nConnection: "
diff --git a/extensions/libarchive/CompressContent.h b/extensions/libarchive/CompressContent.h
index 7fd8e24..3535bb7 100644
--- a/extensions/libarchive/CompressContent.h
+++ b/extensions/libarchive/CompressContent.h
@@ -364,7 +364,7 @@
     int64_t process(std::shared_ptr<io::BaseStream> outputStream) override {
       class ReadCallback : public InputStreamCallback {
        public:
-        ReadCallback(GzipWriteCallback& writer, std::shared_ptr<io::BaseStream> outputStream)
+        ReadCallback(GzipWriteCallback& writer, std::shared_ptr<io::OutputStream> outputStream)
           : writer_(writer)
           , outputStream_(std::move(outputStream)) {
         }
@@ -379,25 +379,25 @@
             } else if (ret == 0) {
               break;
             } else {
-              if (outputStream_->writeData(buffer.data(), ret) != ret) {
+              if (outputStream_->write(buffer.data(), ret) != ret) {
                 return -1;
               }
               read_size += ret;
             }
           }
-          outputStream_->closeStream();
+          outputStream_->close();
           return read_size;
         }
 
         GzipWriteCallback& writer_;
-        std::shared_ptr<io::BaseStream> outputStream_;
+        std::shared_ptr<io::OutputStream> outputStream_;
       };
 
       std::shared_ptr<io::ZlibBaseStream> filterStream;
       if (compress_mode_ == MODE_COMPRESS) {
-        filterStream = std::make_shared<io::ZlibCompressStream>(outputStream.get(), io::ZlibCompressionFormat::GZIP, compress_level_);
+        filterStream = std::make_shared<io::ZlibCompressStream>(gsl::make_not_null(outputStream.get()), io::ZlibCompressionFormat::GZIP, compress_level_);
       } else {
-        filterStream = std::make_shared<io::ZlibDecompressStream>(outputStream.get(), io::ZlibCompressionFormat::GZIP);
+        filterStream = std::make_shared<io::ZlibDecompressStream>(gsl::make_not_null(outputStream.get()), io::ZlibCompressionFormat::GZIP);
       }
       ReadCallback readCb(*this, filterStream);
       session_->read(flow_, &readCb);
diff --git a/extensions/libarchive/FocusArchiveEntry.cpp b/extensions/libarchive/FocusArchiveEntry.cpp
index 9888c87..47ba570 100644
--- a/extensions/libarchive/FocusArchiveEntry.cpp
+++ b/extensions/libarchive/FocusArchiveEntry.cpp
@@ -165,7 +165,7 @@
   int last_read = 0;
 
   do {
-    last_read = data->stream->readData(reinterpret_cast<uint8_t *>(data->buf), 8196 - read);
+    last_read = data->stream->read(reinterpret_cast<uint8_t *>(data->buf), 8196 - read);
     read += last_read;
   } while (data->processor->isRunning() && last_read > 0 && read < 8196);
 
diff --git a/extensions/libarchive/UnfocusArchiveEntry.cpp b/extensions/libarchive/UnfocusArchiveEntry.cpp
index b3273a8..9007b05 100644
--- a/extensions/libarchive/UnfocusArchiveEntry.cpp
+++ b/extensions/libarchive/UnfocusArchiveEntry.cpp
@@ -165,7 +165,7 @@
 la_ssize_t UnfocusArchiveEntry::WriteCallback::write_cb(struct archive *, void *d, const void *buffer, size_t length) {
   auto data = static_cast<UnfocusArchiveEntryWriteData *>(d);
   const uint8_t *ui_buffer = static_cast<const uint8_t*>(buffer);
-  return data->stream->writeData(const_cast<uint8_t*>(ui_buffer), length);
+  return data->stream->write(const_cast<uint8_t*>(ui_buffer), length);
 }
 
 int64_t UnfocusArchiveEntry::WriteCallback::process(std::shared_ptr<io::BaseStream> stream) {
diff --git a/extensions/mqtt/processors/ConvertJSONAck.cpp b/extensions/mqtt/processors/ConvertJSONAck.cpp
index a8f978f..51ec140 100644
--- a/extensions/mqtt/processors/ConvertJSONAck.cpp
+++ b/extensions/mqtt/processors/ConvertJSONAck.cpp
@@ -100,7 +100,7 @@
 
     auto stream = c2::PayloadSerializer::serialize(1,payload);
 
-    mqtt_service_->send(topic, stream->getBuffer(), stream->getSize());
+    mqtt_service_->send(topic, stream->getBuffer(), stream->size());
 
   }
 
diff --git a/extensions/mqtt/processors/ConvertJSONAck.h b/extensions/mqtt/processors/ConvertJSONAck.h
index 0d2cdf8..c99cb1b 100644
--- a/extensions/mqtt/processors/ConvertJSONAck.h
+++ b/extensions/mqtt/processors/ConvertJSONAck.h
@@ -77,8 +77,8 @@
       int64_t ret = 0;
       if (nullptr == stream)
         return 0;
-      buffer_.resize(stream->getSize());
-      ret = stream->read(reinterpret_cast<uint8_t*>(buffer_.data()), stream->getSize());
+      buffer_.resize(stream->size());
+      ret = stream->read(reinterpret_cast<uint8_t*>(buffer_.data()), stream->size());
       return ret;
     }
     std::vector<char> buffer_;
diff --git a/extensions/mqtt/processors/ConvertUpdate.cpp b/extensions/mqtt/processors/ConvertUpdate.cpp
index b0689b0..ac61c8d 100644
--- a/extensions/mqtt/processors/ConvertUpdate.cpp
+++ b/extensions/mqtt/processors/ConvertUpdate.cpp
@@ -18,7 +18,7 @@
 #include "ConvertUpdate.h"
 #include "utils/HTTPClient.h"
 #include "io/BaseStream.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 
 namespace org {
 namespace apache {
@@ -39,8 +39,7 @@
     // first we have the input topic string followed by the update URI
     if (update.size() > 0) {
 
-      io::DataStream dataStream(update.data(), update.size());
-      io::BaseStream stream(&dataStream);
+      io::BufferStream stream(update.data(), update.size());
 
       std::string returnTopic, url;
 
@@ -49,8 +48,8 @@
         break;
       }
 
-      stream.readUTF(returnTopic);
-      stream.readUTF(url);
+      stream.read(returnTopic);
+      stream.read(url);
 
       /**
        * Not having curl support is actually okay for MQTT to be built, but running the update processor requires
diff --git a/extensions/mqtt/protocol/MQTTC2Protocol.cpp b/extensions/mqtt/protocol/MQTTC2Protocol.cpp
index 2dcdf68..8db15a1 100644
--- a/extensions/mqtt/protocol/MQTTC2Protocol.cpp
+++ b/extensions/mqtt/protocol/MQTTC2Protocol.cpp
@@ -64,11 +64,11 @@
 C2Payload MQTTC2Protocol::consumePayload(const std::string &url, const C2Payload &payload, Direction direction, bool async) {
   // we are getting an update.
   std::lock_guard<std::mutex> lock(input_mutex_);
-  io::BaseStream stream;
-  stream.writeUTF(in_topic_);
-  stream.writeUTF(url);
+  io::BufferStream stream;
+  stream.write(in_topic_);
+  stream.write(url);
   std::vector<uint8_t> response;
-  auto transmit_id = mqtt_service_->send(update_topic_, stream.getBuffer(), stream.getSize());
+  auto transmit_id = mqtt_service_->send(update_topic_, stream.getBuffer(), stream.size());
   if (transmit_id > 0 && mqtt_service_->awaitResponse(5000, transmit_id, in_topic_, response)) {
     C2Payload response_payload(payload.getOperation(), state::UpdateState::READ_COMPLETE, true, true);
     response_payload.setRawData(response);
@@ -87,7 +87,7 @@
 
   auto stream = c2::PayloadSerializer::serialize(0x00, payload);
 
-  auto transmit_id = mqtt_service_->send(heartbeat_topic_, stream->getBuffer(), stream->getSize());
+  auto transmit_id = mqtt_service_->send(heartbeat_topic_, stream->getBuffer(), stream->size());
   std::vector<uint8_t> response;
   if (transmit_id > 0 && mqtt_service_->awaitResponse(5000, transmit_id, in_topic_, response)) {
     return c2::PayloadSerializer::deserialize(response);
diff --git a/extensions/opc/src/putopc.cpp b/extensions/opc/src/putopc.cpp
index acc1a63..f02e3f7 100644
--- a/extensions/opc/src/putopc.cpp
+++ b/extensions/opc/src/putopc.cpp
@@ -423,7 +423,7 @@
 
   int64_t PutOPCProcessor::ReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
     buf_.clear();
-    buf_.resize(stream->getSize());
+    buf_.resize(stream->size());
 
     uint64_t size = 0;
 
@@ -438,9 +438,9 @@
         break;
       }
       size += read;
-    } while (size < stream->getSize());
+    } while (size < stream->size());
 
-    logger_->log_trace("Read %llu bytes from flowfile content to buffer", stream->getSize());
+    logger_->log_trace("Read %llu bytes from flowfile content to buffer", stream->size());
 
     return size;
   }
diff --git a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
index 367e374..1d704e5 100644
--- a/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
+++ b/extensions/openwsman/processors/SourceInitiatedSubscriptionListener.cpp
@@ -47,7 +47,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
diff --git a/extensions/rocksdb-repos/DatabaseContentRepository.cpp b/extensions/rocksdb-repos/DatabaseContentRepository.cpp
index 2d4284d..0c93727 100644
--- a/extensions/rocksdb-repos/DatabaseContentRepository.cpp
+++ b/extensions/rocksdb-repos/DatabaseContentRepository.cpp
@@ -84,7 +84,7 @@
     if (outStream == nullptr) {
       throw Exception(REPOSITORY_EXCEPTION, "Couldn't open the underlying resource for write: " + resource.first->getContentFullPath());
     }
-    const auto size = resource.second->getSize();
+    const auto size = resource.second->size();
     if (outStream->write(const_cast<uint8_t*>(resource.second->getBuffer()), size) != size) {
       throw Exception(REPOSITORY_EXCEPTION, "Failed to write new resource: " + resource.first->getContentFullPath());
     }
@@ -94,7 +94,7 @@
     if (outStream == nullptr) {
       throw Exception(REPOSITORY_EXCEPTION, "Couldn't open the underlying resource for append: " + resource.first->getContentFullPath());
     }
-    const auto size = resource.second->getSize();
+    const auto size = resource.second->size();
     if (outStream->write(const_cast<uint8_t*>(resource.second->getBuffer()), size) != size) {
       throw Exception(REPOSITORY_EXCEPTION, "Failed to append to resource: " + resource.first->getContentFullPath());
     }
diff --git a/extensions/rocksdb-repos/FlowFileRepository.h b/extensions/rocksdb-repos/FlowFileRepository.h
index b3cfc2b..40d00e1 100644
--- a/extensions/rocksdb-repos/FlowFileRepository.h
+++ b/extensions/rocksdb-repos/FlowFileRepository.h
@@ -134,14 +134,14 @@
     return ExecuteWithRetry(operation);
   }
 
-  virtual bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<minifi::io::DataStream>>>& data) {
+  virtual bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<minifi::io::BufferStream>>>& data) {
     auto opendb = db_->open();
     if (!opendb) {
       return false;
     }
     rocksdb::WriteBatch batch;
     for (const auto &item: data) {
-      rocksdb::Slice value((const char *) item.second->getBuffer(), item.second->getSize());
+      rocksdb::Slice value((const char *) item.second->getBuffer(), item.second->size());
       if (!batch.Put(item.first, value).ok()) {
         logger_->log_error("Failed to add item to batch operation");
         return false;
diff --git a/extensions/rocksdb-repos/ProvenanceRepository.h b/extensions/rocksdb-repos/ProvenanceRepository.h
index 5b5f788..bee6b9f 100644
--- a/extensions/rocksdb-repos/ProvenanceRepository.h
+++ b/extensions/rocksdb-repos/ProvenanceRepository.h
@@ -125,10 +125,10 @@
     return db_->Put(rocksdb::WriteOptions(), key, value).ok();
   }
 
-  virtual bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<minifi::io::DataStream>>>& data) {
+  virtual bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<minifi::io::BufferStream>>>& data) {
     rocksdb::WriteBatch batch;
     for (const auto &item: data) {
-      rocksdb::Slice value((const char *) item.second->getBuffer(), item.second->getSize());
+      rocksdb::Slice value((const char *) item.second->getBuffer(), item.second->size());
       if (!batch.Put(item.first, value).ok()) {
         return false;
       }
diff --git a/extensions/rocksdb-repos/RocksDbStream.cpp b/extensions/rocksdb-repos/RocksDbStream.cpp
index 8fe6178..933bd29 100644
--- a/extensions/rocksdb-repos/RocksDbStream.cpp
+++ b/extensions/rocksdb-repos/RocksDbStream.cpp
@@ -43,27 +43,15 @@
   size_ = value_.size();
 }
 
-void RocksDbStream::closeStream() {
+void RocksDbStream::close() {
 }
 
 void RocksDbStream::seek(uint64_t offset) {
   // noop
 }
 
-int RocksDbStream::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    return -1;
-  }
-  return writeData(buf.data(), buflen);
-}
-
-// data stream overrides
-
-int RocksDbStream::writeData(uint8_t *value, int size) {
+int RocksDbStream::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
   if (!IsNullOrEmpty(value) && write_enable_) {
     auto opendb = db_->open();
     if (!opendb) {
@@ -89,29 +77,8 @@
   }
 }
 
-template<typename T>
-inline int RocksDbStream::readBuffer(std::vector<uint8_t>& buf, const T& t) {
-  buf.resize(sizeof t);
-  return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-}
-
-int RocksDbStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < gsl::narrow<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int ret = readData(buf.data(), buflen);
-
-  if (ret < buflen) {
-    buf.resize((std::max)(ret, 0));
-  }
-  return ret;
-}
-
-int RocksDbStream::readData(uint8_t *buf, int buflen) {
+int RocksDbStream::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   if (!IsNullOrEmpty(buf) && exists_) {
     size_t amtToRead = gsl::narrow<size_t>(buflen);
     if (offset_ >= value_.size()) {
diff --git a/extensions/rocksdb-repos/RocksDbStream.h b/extensions/rocksdb-repos/RocksDbStream.h
index a762753..3476913 100644
--- a/extensions/rocksdb-repos/RocksDbStream.h
+++ b/extensions/rocksdb-repos/RocksDbStream.h
@@ -24,7 +24,6 @@
 #include <string>
 #include "io/EndianCheck.h"
 #include "io/BaseStream.h"
-#include "io/Serializable.h"
 #include "core/logging/LoggerConfiguration.h"
 
 namespace org {
@@ -49,107 +48,35 @@
   explicit RocksDbStream(std::string path, gsl::not_null<minifi::internal::RocksDatabase*> db, bool write_enable = false, rocksdb::WriteBatch* batch = nullptr);
 
   ~RocksDbStream() override {
-    closeStream();
+    close();
   }
 
-  void closeStream() override;
+  void close() final;
   /**
    * Skip to the specified offset.
    * @param offset offset to which we will skip
    */
   void seek(uint64_t offset) override;
 
-  const size_t getSize() const override {
+  size_t size() const override {
     return size_;
   }
 
-  int read(uint16_t &value, bool is_little_endian) override {
-    uint8_t buf[2];
-    if (readData(&buf[0], 2) < 0)
-      return -1;
-    if (is_little_endian) {
-      value = (buf[0] << 8) | buf[1];
-    } else {
-      value = buf[0] | buf[1] << 8;
-    }
-    return 2;
-  }
-
-  int read(uint32_t &value, bool is_little_endian) override {
-    uint8_t buf[4];
-    if (readData(&buf[0], 4) < 0)
-      return -1;
-
-    if (is_little_endian) {
-      value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-    } else {
-      value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-    }
-
-    return 4;
-  }
-  int read(uint64_t &value, bool is_little_endian) override {
-    uint8_t buf[8];
-    if (readData(&buf[0], 8) < 0)
-      return -1;
-    if (is_little_endian) {
-      value = ((uint64_t) buf[0] << 56) | ((uint64_t) (buf[1] & 255) << 48) | ((uint64_t) (buf[2] & 255) << 40) | ((uint64_t) (buf[3] & 255) << 32) | ((uint64_t) (buf[4] & 255) << 24)
-          | ((uint64_t) (buf[5] & 255) << 16) | ((uint64_t) (buf[6] & 255) << 8) | ((uint64_t) (buf[7] & 255) << 0);
-    } else {
-      value = ((uint64_t) buf[0] << 0) | ((uint64_t) (buf[1] & 255) << 8) | ((uint64_t) (buf[2] & 255) << 16) | ((uint64_t) (buf[3] & 255) << 24) | ((uint64_t) (buf[4] & 255) << 32)
-          | ((uint64_t) (buf[5] & 255) << 40) | ((uint64_t) (buf[6] & 255) << 48) | ((uint64_t) (buf[7] & 255) << 56);
-    }
-    return 8;
-  }
-
-  // data stream extensions
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * writes value to stream
    * @param value value to write
    * @param size size of value
    */
-  int writeData(uint8_t *value, int size) override;
-
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   **/
-  const uint8_t *getBuffer() const {
-    throw std::runtime_error("Stream does not support this operation");
-  }
+  int write(const uint8_t *value, int size) override;
 
  protected:
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read.
-   */
-  template<typename T>
-  int readBuffer(std::vector<uint8_t>&, const T&);
-
   std::string path_;
 
   bool write_enable_;
diff --git a/extensions/script/lua/LuaBaseStream.cpp b/extensions/script/lua/LuaBaseStream.cpp
index 2f97a22..92b52f5 100644
--- a/extensions/script/lua/LuaBaseStream.cpp
+++ b/extensions/script/lua/LuaBaseStream.cpp
@@ -35,7 +35,7 @@
 
 std::string LuaBaseStream::read(size_t len) {
   if (len == 0) {
-    len = stream_->getSize();
+    len = stream_->size();
   }
 
   if (len <= 0) {
@@ -52,7 +52,7 @@
   //     0 <= n < s.size()."
   //
   // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
-  auto read = stream_->readData(reinterpret_cast<uint8_t *>(&buffer[0]), static_cast<int>(len));
+  auto read = stream_->read(reinterpret_cast<uint8_t *>(&buffer[0]), static_cast<int>(len));
 
   if (read != len) {
     buffer.resize(static_cast<size_t >(read));
@@ -62,7 +62,7 @@
 }
 
 size_t LuaBaseStream::write(std::string buf) {
-  return static_cast<size_t>(stream_->writeData(reinterpret_cast<uint8_t *>(const_cast<char *>(buf.data())),
+  return static_cast<size_t>(stream_->write(reinterpret_cast<uint8_t *>(const_cast<char *>(buf.data())),
                                                 static_cast<int>(buf.length())));
 }
 
diff --git a/extensions/script/python/PyBaseStream.cpp b/extensions/script/python/PyBaseStream.cpp
index fac0b3b..fcde480 100644
--- a/extensions/script/python/PyBaseStream.cpp
+++ b/extensions/script/python/PyBaseStream.cpp
@@ -35,12 +35,12 @@
 }
 
 py::bytes PyBaseStream::read() {
-  return read(stream_->getSize());
+  return read(stream_->size());
 }
 
 py::bytes PyBaseStream::read(size_t len) {
   if (len == 0) {
-    len = stream_->getSize();
+    len = stream_->size();
   }
 
   if (len <= 0) {
@@ -49,7 +49,7 @@
 
   std::vector<uint8_t> buffer(len);
 
-  auto read = stream_->readData(buffer.data(), static_cast<int>(len));
+  auto read = stream_->read(buffer.data(), static_cast<int>(len));
   auto result = py::bytes(reinterpret_cast<char *>(buffer.data()), static_cast<size_t>(read));
 
   return result;
@@ -57,7 +57,7 @@
 
 size_t PyBaseStream::write(py::bytes buf) {
   const auto &&buf_str = buf.operator std::string();
-  return static_cast<size_t>(stream_->writeData(reinterpret_cast<uint8_t *>(const_cast<char *>(buf_str.data())),
+  return static_cast<size_t>(stream_->write(reinterpret_cast<uint8_t *>(const_cast<char *>(buf_str.data())),
                                                 static_cast<int>(buf_str.length())));
 }
 
diff --git a/extensions/sensors/GetEnvironmentalSensors.cpp b/extensions/sensors/GetEnvironmentalSensors.cpp
index 36c96a9..a1ef2b6 100644
--- a/extensions/sensors/GetEnvironmentalSensors.cpp
+++ b/extensions/sensors/GetEnvironmentalSensors.cpp
@@ -35,7 +35,7 @@
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
 #include "GetEnvironmentalSensors.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
diff --git a/extensions/sensors/GetMovementSensors.cpp b/extensions/sensors/GetMovementSensors.cpp
index af39cb7..a8bd18a 100644
--- a/extensions/sensors/GetMovementSensors.cpp
+++ b/extensions/sensors/GetMovementSensors.cpp
@@ -34,7 +34,7 @@
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
 #include "GetMovementSensors.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
diff --git a/extensions/sensors/SensorBase.cpp b/extensions/sensors/SensorBase.cpp
index 526826d..98a5d33 100644
--- a/extensions/sensors/SensorBase.cpp
+++ b/extensions/sensors/SensorBase.cpp
@@ -34,7 +34,7 @@
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
 #include "SensorBase.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
diff --git a/extensions/sftp/client/SFTPClient.cpp b/extensions/sftp/client/SFTPClient.cpp
index 8323d87..c56b327 100644
--- a/extensions/sftp/client/SFTPClient.cpp
+++ b/extensions/sftp/client/SFTPClient.cpp
@@ -527,7 +527,7 @@
     total_read += read_ret;
     int remaining = read_ret;
     while (remaining > 0) {
-      int write_ret = output.writeData(buf.data() + (read_ret - remaining), remaining);
+      int write_ret = output.write(buf.data() + (read_ret - remaining), remaining);
       if (write_ret < 0) {
         last_error_ = LIBSSH2_FX_OK;
         logger_->log_error("Failed to write output");
@@ -577,7 +577,7 @@
   std::vector<uint8_t> buf(buf_size);
   uint64_t total_read = 0U;
   do {
-    int read_ret = input.readData(buf.data(), buf.size());
+    int read_ret = input.read(buf.data(), buf.size());
     if (read_ret < 0) {
       last_error_ = LIBSSH2_FX_OK;
       logger_->log_error("Error while reading input");
diff --git a/extensions/sftp/processors/FetchSFTP.cpp b/extensions/sftp/processors/FetchSFTP.cpp
index 52cd990..66865e5 100644
--- a/extensions/sftp/processors/FetchSFTP.cpp
+++ b/extensions/sftp/processors/FetchSFTP.cpp
@@ -34,7 +34,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
@@ -161,7 +161,7 @@
   if (!client_.getFile(remote_file_, *stream)) {
     throw client_.getLastError();
   }
-  return stream->getSize();
+  return stream->size();
 }
 
 void FetchSFTP::onTrigger(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session) {
diff --git a/extensions/sftp/processors/ListSFTP.cpp b/extensions/sftp/processors/ListSFTP.cpp
index 985f3f4..b7936ca 100644
--- a/extensions/sftp/processors/ListSFTP.cpp
+++ b/extensions/sftp/processors/ListSFTP.cpp
@@ -42,7 +42,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 
diff --git a/extensions/sftp/processors/PutSFTP.cpp b/extensions/sftp/processors/PutSFTP.cpp
index 8bb1bc6..d380037 100644
--- a/extensions/sftp/processors/PutSFTP.cpp
+++ b/extensions/sftp/processors/PutSFTP.cpp
@@ -37,7 +37,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
@@ -214,10 +214,10 @@
   if (!client_.putFile(target_path_,
       *stream,
       conflict_resolution_ == CONFLICT_RESOLUTION_REPLACE /*overwrite*/,
-      stream->getSize() /*expected_size*/)) {
+      stream->size() /*expected_size*/)) {
     throw client_.getLastError();
   }
-  return stream->getSize();
+  return stream->size();
 }
 
 bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, const std::shared_ptr<core::ProcessSession> &session) {
diff --git a/extensions/sftp/processors/SFTPProcessorBase.cpp b/extensions/sftp/processors/SFTPProcessorBase.cpp
index 9600362..b6978d4 100644
--- a/extensions/sftp/processors/SFTPProcessorBase.cpp
+++ b/extensions/sftp/processors/SFTPProcessorBase.cpp
@@ -37,7 +37,7 @@
 #include "core/logging/Logger.h"
 #include "core/ProcessContext.h"
 #include "core/Relationship.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/StreamFactory.h"
 #include "ResourceClaim.h"
 #include "utils/StringUtils.h"
diff --git a/extensions/sql/processors/ExecuteSQL.cpp b/extensions/sql/processors/ExecuteSQL.cpp
index fd1097b..93dac9e 100644
--- a/extensions/sql/processors/ExecuteSQL.cpp
+++ b/extensions/sql/processors/ExecuteSQL.cpp
@@ -33,7 +33,7 @@
 
 #include <soci/soci.h>
 
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "Exception.h"
diff --git a/extensions/sql/processors/PutSQL.cpp b/extensions/sql/processors/PutSQL.cpp
index e2375c8..70b8623 100644
--- a/extensions/sql/processors/PutSQL.cpp
+++ b/extensions/sql/processors/PutSQL.cpp
@@ -33,7 +33,7 @@
 
 #include <soci/soci.h>
 
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "Exception.h"
diff --git a/extensions/sql/processors/QueryDatabaseTable.cpp b/extensions/sql/processors/QueryDatabaseTable.cpp
index 0a38dfee..71b0e6f 100644
--- a/extensions/sql/processors/QueryDatabaseTable.cpp
+++ b/extensions/sql/processors/QueryDatabaseTable.cpp
@@ -35,7 +35,7 @@
 
 #include <soci/soci.h>
 
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "Exception.h"
diff --git a/extensions/sqlite/ExecuteSQL.cpp b/extensions/sqlite/ExecuteSQL.cpp
index 51f6dee..9a9a22c 100644
--- a/extensions/sqlite/ExecuteSQL.cpp
+++ b/extensions/sqlite/ExecuteSQL.cpp
@@ -173,9 +173,9 @@
 }
 
 int64_t ExecuteSQL::SQLReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
-  sql_->resize(stream->getSize());
-  auto num_read = static_cast<uint64_t >(stream->readData(reinterpret_cast<uint8_t *>(&(*sql_)[0]),
-                                                          static_cast<int>(stream->getSize())));
+  sql_->resize(stream->size());
+  auto num_read = static_cast<uint64_t >(stream->read(reinterpret_cast<uint8_t *>(&(*sql_)[0]),
+                                                          static_cast<int>(stream->size())));
 
   if (num_read != stream->getSize()) {
     throw std::runtime_error("SQLReadCallback failed to fully read flow file input stream");
diff --git a/extensions/sqlite/PutSQL.cpp b/extensions/sqlite/PutSQL.cpp
index 0143bbb..4eb0ae9 100644
--- a/extensions/sqlite/PutSQL.cpp
+++ b/extensions/sqlite/PutSQL.cpp
@@ -173,11 +173,11 @@
 }
 
 int64_t PutSQL::SQLReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
-  sql_->resize(stream->getSize());
-  auto num_read = static_cast<uint64_t >(stream->readData(reinterpret_cast<uint8_t *>(&(*sql_)[0]),
-                                                          static_cast<int>(stream->getSize())));
+  sql_->resize(stream->size());
+  auto num_read = static_cast<uint64_t >(stream->read(reinterpret_cast<uint8_t *>(&(*sql_)[0]),
+                                                          static_cast<int>(stream->size())));
 
-  if (num_read != stream->getSize()) {
+  if (num_read != stream->size()) {
     throw std::runtime_error("SQLReadCallback failed to fully read flow file input stream");
   }
 
diff --git a/extensions/standard-processors/processors/ExtractText.cpp b/extensions/standard-processors/processors/ExtractText.cpp
index f386a11..d2b1b3b 100644
--- a/extensions/standard-processors/processors/ExtractText.cpp
+++ b/extensions/standard-processors/processors/ExtractText.cpp
@@ -133,7 +133,7 @@
   while (read_size < size_limit) {
     // Don't read more than config limit or the size of the buffer
     int length = gsl::narrow<int>(std::min<uint64_t>(size_limit - read_size, buffer_.size()));
-    ret = stream->readData(buffer_, length);
+    ret = stream->read(buffer_, length);
 
     if (ret < 0) {
       return -1;  // Stream error
diff --git a/extensions/standard-processors/processors/GetTCP.cpp b/extensions/standard-processors/processors/GetTCP.cpp
index 44d89e7..b806b8e 100644
--- a/extensions/standard-processors/processors/GetTCP.cpp
+++ b/extensions/standard-processors/processors/GetTCP.cpp
@@ -166,7 +166,8 @@
       int reconnects = 0;
       do {
         if ( socket_ring_buffer_.try_dequeue(socket_ptr) ) {
-          int size_read = socket_ptr->readData(buffer, gsl::narrow<int>(receive_buffer_size_), false);
+          buffer.resize(receive_buffer_size_);
+          int size_read = socket_ptr->read(buffer.data(), gsl::narrow<int>(receive_buffer_size_), false);
           if (size_read >= 0) {
             if (size_read > 0) {
               // determine cut location
@@ -196,14 +197,14 @@
           } else if (size_read == -2 && stay_connected_) {
             if (++reconnects > connection_attempt_limit_) {
               logger_->log_info("Too many reconnects, exiting thread");
-              socket_ptr->closeStream();
+              socket_ptr->close();
               return -1;
             }
             logger_->log_info("Sleeping for %" PRIu64 " msec before attempting to reconnect", reconnect_interval_);
             std::this_thread::sleep_for(std::chrono::milliseconds(reconnect_interval_));
             socket_ring_buffer_.enqueue(std::move(socket_ptr));
           } else {
-            socket_ptr->closeStream();
+            socket_ptr->close();
             std::this_thread::sleep_for(std::chrono::milliseconds(reconnect_interval_));
             logger_->log_info("Read response returned a -1 from socket, exiting thread");
             return -1;
diff --git a/extensions/standard-processors/processors/HashContent.h b/extensions/standard-processors/processors/HashContent.h
index deccb83..d55a172 100644
--- a/extensions/standard-processors/processors/HashContent.h
+++ b/extensions/standard-processors/processors/HashContent.h
@@ -56,7 +56,7 @@
 
     size_t ret = 0;
     do {
-      ret = stream->readData(buffer, HASH_BUFFER_SIZE);
+      ret = stream->read(buffer, HASH_BUFFER_SIZE);
       if (ret > 0) {
         MD5_Update(&context, buffer, ret);
         ret_val.second += ret;
@@ -80,7 +80,7 @@
 
     size_t ret = 0;
     do {
-      ret = stream->readData(buffer, HASH_BUFFER_SIZE);
+      ret = stream->read(buffer, HASH_BUFFER_SIZE);
       if (ret > 0) {
         SHA1_Update(&context, buffer, ret);
         ret_val.second += ret;
@@ -104,7 +104,7 @@
 
     size_t ret;
     do {
-      ret = stream->readData(buffer, HASH_BUFFER_SIZE);
+      ret = stream->read(buffer, HASH_BUFFER_SIZE);
       if (ret > 0) {
         SHA256_Update(&context, buffer, ret);
         ret_val.second += ret;
diff --git a/extensions/standard-processors/processors/PutFile.cpp b/extensions/standard-processors/processors/PutFile.cpp
index 1d7de94..6f2620a 100644
--- a/extensions/standard-processors/processors/PutFile.cpp
+++ b/extensions/standard-processors/processors/PutFile.cpp
@@ -264,7 +264,7 @@
 
     tmp_file_os.write(reinterpret_cast<char *>(buffer), read);
     size += read;
-  } while (size < stream->getSize());
+  } while (size < stream->size());
 
   tmp_file_os.close();
 
diff --git a/extensions/standard-processors/processors/TailFile.cpp b/extensions/standard-processors/processors/TailFile.cpp
index efa7549..bc40e86 100644
--- a/extensions/standard-processors/processors/TailFile.cpp
+++ b/extensions/standard-processors/processors/TailFile.cpp
@@ -203,7 +203,7 @@
   }
 
   int64_t process(std::shared_ptr<io::BaseStream> output_stream) override {
-    io::CRCStream<io::BaseStream> crc_stream{output_stream.get(), checksum_};
+    io::CRCStream<io::BaseStream> crc_stream{gsl::make_not_null(output_stream.get()), checksum_};
 
     uint64_t num_bytes_written = 0;
     bool found_delimiter = false;
@@ -284,7 +284,7 @@
   int64_t process(std::shared_ptr<io::BaseStream> output_stream) override {
     std::array<char, BUFFER_SIZE> buffer;
 
-    io::CRCStream<io::BaseStream> crc_stream{output_stream.get(), checksum_};
+    io::CRCStream<io::BaseStream> crc_stream{gsl::make_not_null(output_stream.get()), checksum_};
 
     uint64_t num_bytes_written = 0;
 
diff --git a/extensions/standard-processors/tests/unit/GetTCPTests.cpp b/extensions/standard-processors/tests/unit/GetTCPTests.cpp
index 5f86a51..5eb537f 100644
--- a/extensions/standard-processors/tests/unit/GetTCPTests.cpp
+++ b/extensions/standard-processors/tests/unit/GetTCPTests.cpp
@@ -110,7 +110,7 @@
   std::shared_ptr<core::ProcessSessionFactory> factory = std::make_shared<core::ProcessSessionFactory>(context);
   processor->onSchedule(context, factory);
   processor->onTrigger(context, session);
-  server.writeData(buffer, buffer.size());
+  server.write(buffer, buffer.size());
   std::this_thread::sleep_for(std::chrono::seconds(2));
 
   logAttribute->initialize();
@@ -223,7 +223,7 @@
   std::shared_ptr<core::ProcessSessionFactory> factory = std::make_shared<core::ProcessSessionFactory>(context);
   processor->onSchedule(context, factory);
   processor->onTrigger(context, session);
-  server.writeData(buffer, buffer.size());
+  server.write(buffer, buffer.size());
   std::this_thread::sleep_for(std::chrono::seconds(2));
 
   logAttribute->initialize();
@@ -345,7 +345,7 @@
   std::shared_ptr<core::ProcessSessionFactory> factory = std::make_shared<core::ProcessSessionFactory>(context);
   processor->onSchedule(context, factory);
   processor->onTrigger(context, session);
-  server.writeData(buffer, buffer.size());
+  server.write(buffer, buffer.size());
   std::this_thread::sleep_for(std::chrono::seconds(2));
 
   logAttribute->initialize();
diff --git a/extensions/standard-processors/tests/unit/SchedulingAgentTests.cpp b/extensions/standard-processors/tests/unit/SchedulingAgentTests.cpp
index dfd848a..316877a 100644
--- a/extensions/standard-processors/tests/unit/SchedulingAgentTests.cpp
+++ b/extensions/standard-processors/tests/unit/SchedulingAgentTests.cpp
@@ -20,7 +20,7 @@
 #include <string>
 #include <vector>
 #include "io/CRCStream.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "TestBase.h"
 #include "GetFile.h"
 #include "LogAttribute.h"
diff --git a/extensions/tensorflow/TFApplyGraph.cpp b/extensions/tensorflow/TFApplyGraph.cpp
index 8d0092d..bc4aac6 100644
--- a/extensions/tensorflow/TFApplyGraph.cpp
+++ b/extensions/tensorflow/TFApplyGraph.cpp
@@ -190,11 +190,11 @@
 
 int64_t TFApplyGraph::GraphReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
   std::string graph_proto_buf;
-  graph_proto_buf.resize(stream->getSize());
-  auto num_read = stream->readData(reinterpret_cast<uint8_t *>(&graph_proto_buf[0]),
-                                   static_cast<int>(stream->getSize()));
+  graph_proto_buf.resize(stream->size());
+  auto num_read = stream->read(reinterpret_cast<uint8_t *>(&graph_proto_buf[0]),
+                                   static_cast<int>(stream->size()));
 
-  if (num_read != stream->getSize()) {
+  if (num_read != stream->size()) {
     throw std::runtime_error("GraphReadCallback failed to fully read flow file input stream");
   }
 
@@ -204,11 +204,11 @@
 
 int64_t TFApplyGraph::TensorReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
   std::string tensor_proto_buf;
-  tensor_proto_buf.resize(stream->getSize());
-  auto num_read = stream->readData(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
-                                   static_cast<int>(stream->getSize()));
+  tensor_proto_buf.resize(stream->size());
+  auto num_read = stream->read(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
+                                   static_cast<int>(stream->size()));
 
-  if (num_read != stream->getSize()) {
+  if (num_read != stream->size()) {
     throw std::runtime_error("TensorReadCallback failed to fully read flow file input stream");
   }
 
@@ -218,7 +218,7 @@
 
 int64_t TFApplyGraph::TensorWriteCallback::process(std::shared_ptr<io::BaseStream> stream) {
   auto tensor_proto_buf = tensor_proto_->SerializeAsString();
-  auto num_wrote = stream->writeData(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
+  auto num_wrote = stream->write(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
                                      static_cast<int>(tensor_proto_buf.size()));
 
   if (num_wrote != tensor_proto_buf.size()) {
diff --git a/extensions/tensorflow/TFConvertImageToTensor.cpp b/extensions/tensorflow/TFConvertImageToTensor.cpp
index 5b2ace0..bdc86e4 100644
--- a/extensions/tensorflow/TFConvertImageToTensor.cpp
+++ b/extensions/tensorflow/TFConvertImageToTensor.cpp
@@ -318,14 +318,14 @@
 }
 
 int64_t TFConvertImageToTensor::ImageReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
-  if (tensor_->AllocatedBytes() < stream->getSize()) {
+  if (tensor_->AllocatedBytes() < stream->size()) {
     throw std::runtime_error("Tensor is not big enough to hold FlowFile bytes");
   }
 
-  auto num_read = stream->readData(tensor_->flat<unsigned char>().data(),
-                                   static_cast<int>(stream->getSize()));
+  auto num_read = stream->read(tensor_->flat<unsigned char>().data(),
+                                   static_cast<int>(stream->size()));
 
-  if (num_read != stream->getSize()) {
+  if (num_read != stream->size()) {
     throw std::runtime_error("TensorReadCallback failed to fully read flow file input stream");
   }
 
@@ -334,7 +334,7 @@
 
 int64_t TFConvertImageToTensor::TensorWriteCallback::process(std::shared_ptr<io::BaseStream> stream) {
   auto tensor_proto_buf = tensor_proto_->SerializeAsString();
-  auto num_wrote = stream->writeData(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
+  auto num_wrote = stream->write(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
                                      static_cast<int>(tensor_proto_buf.size()));
 
   if (num_wrote != tensor_proto_buf.size()) {
diff --git a/extensions/tensorflow/TFExtractTopLabels.cpp b/extensions/tensorflow/TFExtractTopLabels.cpp
index 723f7dc..dab3071 100644
--- a/extensions/tensorflow/TFExtractTopLabels.cpp
+++ b/extensions/tensorflow/TFExtractTopLabels.cpp
@@ -154,11 +154,11 @@
 
 int64_t TFExtractTopLabels::TensorReadCallback::process(std::shared_ptr<io::BaseStream> stream) {
   std::string tensor_proto_buf;
-  tensor_proto_buf.resize(stream->getSize());
-  auto num_read = stream->readData(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
-                                   static_cast<int>(stream->getSize()));
+  tensor_proto_buf.resize(stream->size());
+  auto num_read = stream->read(reinterpret_cast<uint8_t *>(&tensor_proto_buf[0]),
+                                   static_cast<int>(stream->size()));
 
-  if (num_read != stream->getSize()) {
+  if (num_read != stream->size()) {
     throw std::runtime_error("TensorReadCallback failed to fully read flow file input stream");
   }
 
diff --git a/extensions/usb-camera/GetUSBCamera.cpp b/extensions/usb-camera/GetUSBCamera.cpp
index c5518a6..ec2d40f 100644
--- a/extensions/usb-camera/GetUSBCamera.cpp
+++ b/extensions/usb-camera/GetUSBCamera.cpp
@@ -453,7 +453,7 @@
     throw;
   }
 
-  return stream->writeData(png_output_buf_.data(), png_output_buf_.size());
+  return stream->write(png_output_buf_.data(), png_output_buf_.size());
 }
 
 GetUSBCamera::RawWriteCallback::RawWriteCallback(uvc_frame_t *frame)
@@ -463,7 +463,7 @@
 
 int64_t GetUSBCamera::RawWriteCallback::process(std::shared_ptr<io::BaseStream> stream) {
   logger_->log_info("Writing %d bytes of raw capture data", frame_->data_bytes);
-  return stream->writeData(reinterpret_cast<uint8_t *>(frame_->data), frame_->data_bytes);
+  return stream->write(reinterpret_cast<uint8_t *>(frame_->data), frame_->data_bytes);
 }
 
 } /* namespace processors */
diff --git a/extensions/windows-event-log/CollectorInitiatedSubscription.cpp b/extensions/windows-event-log/CollectorInitiatedSubscription.cpp
index 31fdf11..b8f94fb 100644
--- a/extensions/windows-event-log/CollectorInitiatedSubscription.cpp
+++ b/extensions/windows-event-log/CollectorInitiatedSubscription.cpp
@@ -30,7 +30,7 @@
 #include <memory>
 #include <codecvt>
 
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 
@@ -634,7 +634,7 @@
     }
 
     int64_t process(std::shared_ptr<io::BaseStream> stream) {
-      return stream->writeData((uint8_t*)&str_[0], str_.size());
+      return stream->write((uint8_t*)&str_[0], str_.size());
     }
 
     std::string str_;
diff --git a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
index 0f3fc00..8c16ea5 100644
--- a/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
+++ b/extensions/windows-event-log/ConsumeWindowsEventLog.cpp
@@ -35,7 +35,7 @@
 #include "wel/XMLString.h"
 #include "wel/UnicodeConversion.h"
 
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 #include "Bookmark.h"
@@ -645,7 +645,7 @@
     }
 
     int64_t process(std::shared_ptr<io::BaseStream> stream) {
-      return stream->writeData(reinterpret_cast<uint8_t*>(const_cast<char*>(str_.c_str())), str_.size());
+      return stream->write(reinterpret_cast<uint8_t*>(const_cast<char*>(str_.c_str())), str_.size());
     }
 
     const std::string& str_;
diff --git a/extensions/windows-event-log/TailEventLog.cpp b/extensions/windows-event-log/TailEventLog.cpp
index 399d38a..7ba7eb0 100644
--- a/extensions/windows-event-log/TailEventLog.cpp
+++ b/extensions/windows-event-log/TailEventLog.cpp
@@ -28,7 +28,7 @@
 #include <string>
 #include <iostream>
 
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/ProcessContext.h"
 #include "core/ProcessSession.h"
 
@@ -114,7 +114,7 @@
       flowFile->addAttribute("event_time", getTimeStamp(event_record->TimeGenerated));
       flowFile->addAttribute("event_type", typeToString(event_record->EventType));
       
-      io::DataStream stream((const uint8_t*)(event_record + event_record->DataOffset), event_record->DataLength);
+      io::BufferStream stream((const uint8_t*)(event_record + event_record->DataOffset), event_record->DataLength);
       // need an import from the data stream.
       session->importFrom(stream, flowFile);
       session->transfer(flowFile, Success);
diff --git a/libminifi/include/FlowFileRecord.h b/libminifi/include/FlowFileRecord.h
index 7c80aef..df7e7ee 100644
--- a/libminifi/include/FlowFileRecord.h
+++ b/libminifi/include/FlowFileRecord.h
@@ -33,7 +33,6 @@
 #include <set>
 #include "core/ContentRepository.h"
 #include "io/BaseStream.h"
-#include "io/Serializable.h"
 #include "core/FlowFile.h"
 #include "utils/TimeUtil.h"
 #include "core/logging/LoggerConfiguration.h"
@@ -96,7 +95,7 @@
   virtual int64_t process(std::shared_ptr<io::BaseStream> stream) = 0;
 };
 
-class FlowFileRecord : public core::FlowFile, public io::Serializable {
+class FlowFileRecord : public core::FlowFile {
  public:
   // Constructor
   /*
@@ -127,15 +126,15 @@
   // getAttribute key is enum
   bool getKeyedAttribute(FlowAttribute key, std::string &value);
 
-  bool Serialize(io::DataStream &outStream);
+  bool Serialize(io::BufferStream &outStream);
 
   //! Serialize and Persistent to the repository
   bool Serialize();
   //! DeSerialize
   bool DeSerialize(const uint8_t *buffer, const int bufferSize);
   //! DeSerialize
-  bool DeSerialize(io::DataStream &stream) {
-    return DeSerialize(stream.getBuffer(), gsl::narrow<int>(stream.getSize()));
+  bool DeSerialize(io::BufferStream &stream) {
+    return DeSerialize(stream.getBuffer(), gsl::narrow<int>(stream.size()));
   }
   //! DeSerialize
   bool DeSerialize(std::string key);
diff --git a/libminifi/include/c2/PayloadSerializer.h b/libminifi/include/c2/PayloadSerializer.h
index df6c24f..0efd133 100644
--- a/libminifi/include/c2/PayloadSerializer.h
+++ b/libminifi/include/c2/PayloadSerializer.h
@@ -69,7 +69,7 @@
       auto str = base_type->getStringValue();
       type = 4;
       stream->write(&type, 1);
-      stream->writeUTF(str);
+      stream->write(str);
     }
   }
   static void serialize(uint16_t op, const C2Payload &payload, std::shared_ptr<io::BaseStream> stream) {
@@ -80,17 +80,17 @@
       op = opToInt(nested_payload.getOperation());
       stream->write(op);
       stream->write(&st, 1);
-      stream->writeUTF(nested_payload.getLabel());
-      stream->writeUTF(nested_payload.getIdentifier());
+      stream->write(nested_payload.getLabel());
+      stream->write(nested_payload.getIdentifier());
       const std::vector<C2ContentResponse> &content = nested_payload.getContent();
       size = content.size();
       stream->write(size);
       for (const auto &payload_content : content) {
-        stream->writeUTF(payload_content.name);
+        stream->write(payload_content.name);
         size = payload_content.operation_arguments.size();
         stream->write(size);
         for (auto content : payload_content.operation_arguments) {
-          stream->writeUTF(content.first);
+          stream->write(content.first);
           serializeValueNode(content.second, stream);
         }
       }
@@ -135,7 +135,7 @@
     return op;
   }
   static std::shared_ptr<io::BaseStream> serialize(uint16_t version, const C2Payload &payload) {
-    std::shared_ptr<io::BaseStream> stream = std::make_shared<io::BaseStream>();
+    std::shared_ptr<io::BaseStream> stream = std::make_shared<io::BufferStream>();
     uint16_t op = 0;
     uint8_t st = 0;
     op = opToInt(payload.getOperation());
@@ -148,18 +148,18 @@
       st = 0;
       stream->write(&st, 1);
     }
-    stream->writeUTF(payload.getLabel());
+    stream->write(payload.getLabel());
 
-    stream->writeUTF(payload.getIdentifier());
+    stream->write(payload.getIdentifier());
     const std::vector<C2ContentResponse> &content = payload.getContent();
     uint32_t size = content.size();
     stream->write(size);
     for (const auto &payload_content : content) {
-      stream->writeUTF(payload_content.name);
+      stream->write(payload_content.name);
       size = payload_content.operation_arguments.size();
       stream->write(size);
       for (auto content : payload_content.operation_arguments) {
-        stream->writeUTF(content.first);
+        stream->write(content.first);
         serializeValueNode(content.second, stream);
       }
     }
@@ -192,7 +192,7 @@
       default:
       case 4:
         std::string str;
-        stream->readUTF(str);
+        stream->read(str);
         node = str;
     }
     return node;
@@ -219,8 +219,8 @@
     for (size_t i = 0; i < payloads; i++) {
       stream->read(op);
       stream->read(st);
-      stream->readUTF(label);
-      stream->readUTF(identifier);
+      stream->read(label);
+      stream->read(identifier);
       operation = intToOp(op);
       C2Payload subPayload(operation, st == 1 ? state::UpdateState::NESTED : state::UpdateState::READ_COMPLETE);
       subPayload.setIdentifier(identifier);
@@ -231,12 +231,12 @@
         std::string content_name;
         uint32_t args = 0;
         C2ContentResponse content(operation);
-        stream->readUTF(content_name);
+        stream->read(content_name);
         content.name = content_name;
         stream->read(args);
         for (uint32_t j = 0; j < args; j++) {
           std::string first, second;
-          stream->readUTF(first);
+          stream->read(first);
           content.operation_arguments[first] = deserializeValueNode(stream);
         }
         subPayload.addContent(std::move(content));
@@ -247,8 +247,7 @@
     return true;
   }
   static bool deserialize(std::vector<uint8_t> data, C2Payload &payload) {
-    io::DataStream dataStream(data.data(), data.size());
-    io::BaseStream stream(&dataStream);
+    io::BufferStream stream(data.data(), data.size());
 
     uint8_t op, st = 0;
     uint16_t version = 0;
@@ -258,8 +257,8 @@
     stream.read(op);
     stream.read(version);
     stream.read(st);
-    stream.readUTF(label);
-    stream.readUTF(identifier);
+    stream.read(label);
+    stream.read(identifier);
 
     Operation operation = intToOp(op);
 
@@ -273,12 +272,12 @@
       std::string content_name;
       uint32_t args = 0;
       C2ContentResponse content(operation);
-      stream.readUTF(content_name);
+      stream.read(content_name);
       content.name = content_name;
       stream.read(args);
       for (uint32_t j = 0; j < args; j++) {
         std::string first, second;
-        stream.readUTF(first);
+        stream.read(first);
         // stream.readUTF(second);
         content.operation_arguments[first] = deserializeValueNode(&stream);
       }
diff --git a/libminifi/include/core/ClassLoader.h b/libminifi/include/core/ClassLoader.h
index 6e7b332..ca3da01 100644
--- a/libminifi/include/core/ClassLoader.h
+++ b/libminifi/include/core/ClassLoader.h
@@ -36,7 +36,7 @@
 #define DLL_EXPORT __declspec(dllexport)
 #endif
 #include "core/Core.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 
 namespace org {
 namespace apache {
diff --git a/libminifi/include/core/ContentRepository.h b/libminifi/include/core/ContentRepository.h
index 68c44fd..68818c1 100644
--- a/libminifi/include/core/ContentRepository.h
+++ b/libminifi/include/core/ContentRepository.h
@@ -24,7 +24,7 @@
 
 #include "properties/Configure.h"
 #include "ResourceClaim.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/BaseStream.h"
 #include "StreamManager.h"
 #include "core/Connectable.h"
diff --git a/libminifi/include/core/ContentSession.h b/libminifi/include/core/ContentSession.h
index a7144f3..2106f0c 100644
--- a/libminifi/include/core/ContentSession.h
+++ b/libminifi/include/core/ContentSession.h
@@ -53,8 +53,8 @@
   virtual ~ContentSession() = default;
 
  protected:
-  std::map<std::shared_ptr<ResourceClaim>, std::shared_ptr<io::BaseStream>> managedResources_;
-  std::map<std::shared_ptr<ResourceClaim>, std::shared_ptr<io::BaseStream>> extendedResources_;
+  std::map<std::shared_ptr<ResourceClaim>, std::shared_ptr<io::BufferStream>> managedResources_;
+  std::map<std::shared_ptr<ResourceClaim>, std::shared_ptr<io::BufferStream>> extendedResources_;
   std::shared_ptr<ContentRepository> repository_;
 };
 
diff --git a/libminifi/include/core/ProcessSession.h b/libminifi/include/core/ProcessSession.h
index 7d0f535..8ed3209 100644
--- a/libminifi/include/core/ProcessSession.h
+++ b/libminifi/include/core/ProcessSession.h
@@ -112,7 +112,7 @@
    * @param stream incoming data stream that contains the data to store into a file
    * @param flow flow file
    */
-  void importFrom(io::DataStream &stream, const std::shared_ptr<core::FlowFile> &flow);
+  void importFrom(io::InputStream &stream, const std::shared_ptr<core::FlowFile> &flow);
   // import from the data source.
   void import(std::string source, const std::shared_ptr<core::FlowFile> &flow, bool keepSource = true, uint64_t offset = 0);
   DEPRECATED(/*deprecated in*/ 0.7.0, /*will remove in */ 2.0) void import(std::string source, std::vector<std::shared_ptr<FlowFileRecord>> &flows, bool keepSource, uint64_t offset, char inputDelimiter); // NOLINT
diff --git a/libminifi/include/core/Repository.h b/libminifi/include/core/Repository.h
index 0741323..2b7d7aa 100644
--- a/libminifi/include/core/Repository.h
+++ b/libminifi/include/core/Repository.h
@@ -37,7 +37,6 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "core/Property.h"
 #include "ResourceClaim.h"
-#include "io/Serializable.h"
 #include "utils/TimeUtil.h"
 #include "utils/StringUtils.h"
 #include "Core.h"
@@ -96,7 +95,7 @@
     return true;
   }
 
-  virtual bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<io::DataStream>>>& data) {
+  virtual bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<io::BufferStream>>>& data) {
     return true;
   }
 
diff --git a/libminifi/include/core/SerializableComponent.h b/libminifi/include/core/SerializableComponent.h
index e2690ea..43e9d20 100644
--- a/libminifi/include/core/SerializableComponent.h
+++ b/libminifi/include/core/SerializableComponent.h
@@ -21,7 +21,6 @@
 #include <memory>
 #include <string>
 
-#include "io/Serializable.h"
 #include "core/Connectable.h"
 #include "core/Core.h"
 
@@ -34,7 +33,7 @@
 /**
  * Represents a component that is serializable and an extension point of core Component
  */
-class SerializableComponent : public core::Connectable, public minifi::io::Serializable {
+class SerializableComponent : public core::Connectable {
  public:
   SerializableComponent(const std::string name) // NOLINT
         : core::Connectable(name) {
diff --git a/libminifi/include/core/StreamManager.h b/libminifi/include/core/StreamManager.h
index 46a9e20..9697f12 100644
--- a/libminifi/include/core/StreamManager.h
+++ b/libminifi/include/core/StreamManager.h
@@ -23,7 +23,7 @@
 
 #include "properties/Configure.h"
 #include "ResourceClaim.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/BaseStream.h"
 
 namespace org {
diff --git a/libminifi/include/core/repository/VolatileRepository.h b/libminifi/include/core/repository/VolatileRepository.h
index a5b395a..9f9dfe3 100644
--- a/libminifi/include/core/repository/VolatileRepository.h
+++ b/libminifi/include/core/repository/VolatileRepository.h
@@ -98,7 +98,7 @@
    * Places new objects into the volatile memory area
    * @param data the key-value pairs to add to the repository
    **/
-  virtual bool MultiPut(const std::vector<std::pair<T, std::unique_ptr<io::DataStream>>>& data);
+  virtual bool MultiPut(const std::vector<std::pair<T, std::unique_ptr<io::BufferStream>>>& data);
 
   /**
    * Deletes the key
@@ -294,9 +294,9 @@
 }
 
 template<typename T>
-bool VolatileRepository<T>::MultiPut(const std::vector<std::pair<T, std::unique_ptr<io::DataStream>>>& data) {
+bool VolatileRepository<T>::MultiPut(const std::vector<std::pair<T, std::unique_ptr<io::BufferStream>>>& data) {
   for (const auto& item : data) {
-    if (!Put(item.first, item.second->getBuffer(), item.second->getSize())) {
+    if (!Put(item.first, item.second->getBuffer(), item.second->size())) {
       return false;
     }
   }
diff --git a/libminifi/include/io/AtomicEntryStream.h b/libminifi/include/io/AtomicEntryStream.h
index c772cd3..4be2847 100644
--- a/libminifi/include/io/AtomicEntryStream.h
+++ b/libminifi/include/io/AtomicEntryStream.h
@@ -54,7 +54,7 @@
 
   ~AtomicEntryStream() override;
 
-  void closeStream() override {
+  void close() override {
   }
 
   /**
@@ -63,47 +63,25 @@
    */
   void seek(uint64_t offset) override;
 
-  const size_t getSize() const override {
+  size_t size() const override {
     return length_;
   }
 
-  // data stream extensions
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * writes value to stream
    * @param value value to write
    * @param size size of value
    */
-  int writeData(uint8_t *value, int size) override;
+  int write(const uint8_t *value, int size) override;
 
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   **/
-  const uint8_t *getBuffer() const {
-    throw std::runtime_error("Stream does not support this operation");
-  }
-
- protected:
+ private:
   size_t length_;
   size_t offset_;
   T key_;
@@ -127,26 +105,16 @@
   offset_ = gsl::narrow<size_t>(offset);
 }
 
-template<typename T>
-int AtomicEntryStream<T>::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen) || invalid_stream_)
-    return -1;
-  return writeData(buf.data(), buflen);
-}
-
 // data stream overrides
 template<typename T>
-int AtomicEntryStream<T>::writeData(uint8_t *value, int size) {
+int AtomicEntryStream<T>::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
   if (size == 0) {
     return 0;
   }
   if (nullptr != value && !invalid_stream_) {
     std::lock_guard<std::recursive_mutex> lock(entry_lock_);
-    if (entry_->insert(key_, value, size)) {
+    if (entry_->insert(key_, const_cast<uint8_t*>(value), size)) {
       offset_ += size;
       if (offset_ > length_) {
         length_ = offset_;
@@ -158,27 +126,8 @@
 }
 
 template<typename T>
-int AtomicEntryStream<T>::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (invalid_stream_) {
-    return -1;
-  }
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int ret = readData(buf.data(), buflen);
-
-  if (ret < buflen) {
-    buf.resize((std::max)(ret, 0));
-  }
-  return ret;
-}
-
-template<typename T>
-int AtomicEntryStream<T>::readData(uint8_t *buf, int buflen) {
+int AtomicEntryStream<T>::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   if (buflen == 0) {
     return 0;
   }
diff --git a/libminifi/include/io/BaseStream.h b/libminifi/include/io/BaseStream.h
index 6b90cab..bff331f 100644
--- a/libminifi/include/io/BaseStream.h
+++ b/libminifi/include/io/BaseStream.h
@@ -16,17 +16,15 @@
  * limitations under the License.
  */
 
-#ifndef LIBMINIFI_INCLUDE_IO_BASESTREAM_H_
-#define LIBMINIFI_INCLUDE_IO_BASESTREAM_H_
+#pragma once
 
 #include <string>
 #include <vector>
 #include <iostream>
 #include <cstdint>
-#include "EndianCheck.h"
-#include "DataStream.h"
-#include "Serializable.h"
 #include "core/expect.h"
+#include "InputStream.h"
+#include "OutputStream.h"
 
 namespace org {
 namespace apache {
@@ -42,166 +40,10 @@
  *
  * Extensions may be thread safe and thus shareable, but that is up to the implementation.
  */
-class BaseStream : public DataStream, public Serializable {
- public:
-  BaseStream()
-      : composable_stream_(this) {
-  }
-
-  BaseStream(DataStream *other) // NOLINT
-      : composable_stream_(other) {
-  }
-
-  ~BaseStream() override = default;
-
-  /**
-   * write 4 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  virtual int write(uint32_t base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  int writeData(uint8_t *value, int size) override;
-
-  void seek(uint64_t offset) override {
-    if (LIKELY(composable_stream_ != this)) {
-      composable_stream_->seek(offset);
-    } else {
-      DataStream::seek(offset);
-    }
-  }
-
-  /**
-   * write 2 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  virtual int write(uint16_t base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * write valueto stream
-   * @param value non encoded value
-   * @param len length of value
-   * @param strema output stream
-   * @return resulting write size
-   **/
-  virtual int write(uint8_t *value, int len);
-
-  /**
-   * write 8 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  virtual int write(uint64_t base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * write bool to stream
-   * @param value non encoded value
-   * @return resulting write size
-   **/
-  virtual int write(bool value);
-
-  /**
-   * write UTF string to stream
-   * @param str string to write
-   * @return resulting write size
-   **/
-  virtual int writeUTF(std::string str, bool widen = false);
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(uint8_t &value);
-
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * reads two bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint16_t &base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(char &value);
-
-  /**
-   * reads a byte array from the stream
-   * @param value reference in which will set the result
-   * @param len length to read
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(uint8_t *value, int len);
-
-  /**
-   * reads four bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint32_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  /**
-   * reads eight byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint64_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  const size_t getSize() const override {
-    if (LIKELY(composable_stream_ == this)) {
-      return buffer.size();
-    } else {
-      return composable_stream_->getSize();
-    }
-  }
-
-  /**
-   * read UTF from stream
-   * @param str reference string
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int readUTF(std::string &str, bool widen = false);
-
- protected:
-  /**
-   * Changed to private to facilitate easier management of composable_stream_ and make it immutable
-   */
-  DataStream *composable_stream_;
-};
+class BaseStream : public InputStream, public OutputStream {};
 
 }  // namespace io
 }  // namespace minifi
 }  // namespace nifi
 }  // namespace apache
 }  // namespace org
-#endif  // LIBMINIFI_INCLUDE_IO_BASESTREAM_H_
diff --git a/libminifi/include/io/BufferStream.h b/libminifi/include/io/BufferStream.h
new file mode 100644
index 0000000..34b0430
--- /dev/null
+++ b/libminifi/include/io/BufferStream.h
@@ -0,0 +1,85 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <iostream>
+#include <cstdint>
+#include <vector>
+#include "BaseStream.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+class BufferStream : public BaseStream {
+ public:
+  BufferStream() = default;
+
+  BufferStream(const uint8_t *buf, const unsigned int len) {
+    write(buf, len);
+  }
+
+  using BaseStream::read;
+  using BaseStream::write;
+
+  int write(const uint8_t* data, int len) final;
+
+  int read(uint8_t* buffer, int len) override;
+
+  int initialize() override {
+    buffer_.clear();
+    readOffset_ = 0;
+    return 0;
+  }
+
+  void seek(uint64_t offset) override {
+    readOffset_ += offset;
+  }
+
+  void close() override { }
+
+  /**
+   * Returns the underlying buffer
+   * @return vector's array
+   **/
+  const uint8_t *getBuffer() const override {
+    return buffer_.data();
+  }
+
+  /**
+   * Retrieve size of data stream
+   * @return size of data stream
+   **/
+  size_t size() const override {
+    return buffer_.size();
+  }
+
+ private:
+  std::vector<uint8_t> buffer_;
+
+  uint64_t readOffset_ = 0;
+};
+
+}  // namespace io
+}  // namespace minifi
+}  // namespace nifi
+}  // namespace apache
+}  // namespace org
diff --git a/libminifi/include/io/CRCStream.h b/libminifi/include/io/CRCStream.h
index eeb24d9..2204537 100644
--- a/libminifi/include/io/CRCStream.h
+++ b/libminifi/include/io/CRCStream.h
@@ -24,6 +24,7 @@
 #include <memory>
 #include <utility>
 #include <vector>
+#include <cassert>
 
 #ifdef WIN32
 #include <winsock2.h>
@@ -34,307 +35,111 @@
 #endif
 #include "BaseStream.h"
 #include "Exception.h"
-#include "Serializable.h"
 
 namespace org {
 namespace apache {
 namespace nifi {
 namespace minifi {
 namespace io {
+namespace internal {
 
-template<typename T>
-class CRCStream : public BaseStream {
+template<typename StreamType>
+class CRCStreamBase : public virtual Stream {
  public:
-  /**
-   * Raw pointer because the caller guarantees that
-   * it will exceed our lifetime.
-   */
-  explicit CRCStream(T *child_stream);
-  CRCStream(T *child_stream, uint64_t initial_crc);
-
-  CRCStream(CRCStream<T>&&) noexcept;
-
-  ~CRCStream() override = default;
-
-  T *getstream() const {
+  StreamType *getstream() const {
     return child_stream_;
   }
 
-  void disableEncoding() {
-    disable_encoding_ = true;
-  }
+  void close() override { child_stream_->close(); }
 
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
-
-  /**
-   * writes value to stream
-   * @param value value to write
-   * @param size size of value
-   */
-  int writeData(uint8_t *value, int size) override;
-
-  using BaseStream::write;
-
-  /**
-   * write 4 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  int write(uint32_t base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-  /**
-   * write 2 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  int write(uint16_t base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  /**
-   * write 8 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  int write(uint64_t base_value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  /**
-   * Reads a system word
-   * @param value value to write
-   */
-  int read(uint64_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  /**
-   * Reads a uint32_t
-   * @param value value to write
-   */
-  int read(uint32_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  /**
-   * Reads a system short
-   * @param value value to write
-   */
-  int read(uint16_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE) override;
-
-  const size_t getSize() const override { return child_stream_->getSize(); }
-
-  void closeStream() override { child_stream_->closeStream(); }
-
-  short initialize() override { // NOLINT
+  int initialize() override {
     child_stream_->initialize();
     reset();
     return 0;
   }
 
-  void updateCRC(uint8_t *buffer, uint32_t length);
+  void updateCRC(uint8_t *buffer, uint32_t length) {
+    crc_ = crc32(crc_, buffer, length);
+  }
 
   uint64_t getCRC() {
-    return crc_;
+    return gsl::narrow<uint64_t>(crc_);
   }
 
-  void reset();
+  void reset() {
+    crc_ = crc32(0L, Z_NULL, 0);
+  }
 
  protected:
-  /**
-   * Creates a vector and returns the vector using the provided
-   * type name.
-   * @param t incoming object
-   * @returns vector.
-   */
-  template<typename K>
-  std::vector<uint8_t> readBuffer(const K& t) {
-    std::vector<uint8_t> buf;
-    readBuffer(buf, t);
-    return buf;
-  }
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read.
-   */
-  template<typename K>
-  int readBuffer(std::vector<uint8_t>& buf, const K& t) {
-    buf.resize(sizeof t);
-    return readData(reinterpret_cast<uint8_t*>(buf.data()), sizeof(t));
-  }
-
-  uLong crc_;
-  T *child_stream_;
-  bool disable_encoding_;
+  uLong crc_ = 0;
+  StreamType* child_stream_ = nullptr;
 };
 
-template<typename T>
-CRCStream<T>::CRCStream(T *child_stream)
-    : child_stream_(child_stream),
-      disable_encoding_(false) {
-  crc_ = crc32(0L, Z_NULL, 0);
-}
+template<typename StreamType>
+class InputCRCStream : public virtual CRCStreamBase<StreamType>, public InputStream {
+ protected:
+  using CRCStreamBase<StreamType>::child_stream_;
+  using CRCStreamBase<StreamType>::crc_;
 
-template<typename T>
-CRCStream<T>::CRCStream(T *child_stream, uint64_t initial_crc)
-    : crc_(gsl::narrow<uLong>(initial_crc)),
-      child_stream_(child_stream),
-      disable_encoding_(false) {
-}
+ public:
+  using InputStream::read;
 
-template<typename T>
-CRCStream<T>::CRCStream(CRCStream<T> &&move) noexcept
-    : crc_(std::move(move.crc_)),
-      child_stream_(std::move(move.child_stream_)),
-      disable_encoding_(false) {
-}
-
-template<typename T>
-int CRCStream<T>::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
+  int read(uint8_t *buf, int buflen) override {
+    int ret = child_stream_->read(buf, buflen);
+    if (ret > 0) {
+      crc_ = crc32(crc_, buf, ret);
+    }
+    return ret;
   }
 
-  if (buf.size() < static_cast<size_t>(buflen))
-    buf.resize(buflen);
-  return readData(buf.data(), buflen);
-}
+  size_t size() const override { return child_stream_->size(); }
+};
 
-template<typename T>
-int CRCStream<T>::readData(uint8_t *buf, int buflen) {
-  int ret = child_stream_->read(buf, buflen);
-  if (ret > 0) {
-    crc_ = crc32(crc_, buf, ret);
+template<typename StreamType>
+class OutputCRCStream : public virtual CRCStreamBase<StreamType>, public OutputStream {
+ protected:
+  using CRCStreamBase<StreamType>::child_stream_;
+  using CRCStreamBase<StreamType>::crc_;
+
+ public:
+  using OutputStream::write;
+
+  int write(const uint8_t *value, int size) override {
+    int ret = child_stream_->write(value, size);
+    if (ret > 0) {
+      crc_ = crc32(crc_, value, ret);
+    }
+    return ret;
   }
-  return ret;
-}
+};
 
-template<typename T>
-int CRCStream<T>::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
+struct empty_class {};
+
+}  // namespace internal
+
+template<typename StreamType>
+class CRCStream : public std::conditional<std::is_base_of<InputStream, StreamType>::value, internal::InputCRCStream<StreamType>, internal::empty_class>::type
+                  , public std::conditional<std::is_base_of<OutputStream, StreamType>::value, internal::OutputCRCStream<StreamType>, internal::empty_class>::type {
+  using internal::CRCStreamBase<StreamType>::child_stream_;
+  using internal::CRCStreamBase<StreamType>::crc_;
+
+ public:
+  explicit CRCStream(gsl::not_null<StreamType*> child_stream) {
+    child_stream_ = child_stream;
+    crc_ = crc32(0L, Z_NULL, 0);
   }
 
-  if (buf.size() < static_cast<size_t>(buflen))
-    buf.resize(buflen);
-  return writeData(buf.data(), buflen);
-}
-
-template<typename T>
-int CRCStream<T>::writeData(uint8_t *value, int size) {
-  int ret = child_stream_->write(value, size);
-  if (ret > 0) {
-    crc_ = crc32(crc_, value, ret);
-  }
-  return ret;
-}
-template<typename T>
-void CRCStream<T>::reset() {
-  crc_ = crc32(0L, Z_NULL, 0);
-}
-template<typename T>
-void CRCStream<T>::updateCRC(uint8_t *buffer, uint32_t length) {
-  crc_ = crc32(crc_, buffer, length);
-}
-
-template<typename T>
-int CRCStream<T>::write(uint64_t base_value, bool is_little_endian) {
-  if (disable_encoding_)
-    is_little_endian = false;
-  const uint64_t value = is_little_endian == 1 ? byteSwap(base_value) : base_value;
-  uint8_t bytes[sizeof value];
-  std::copy(static_cast<const char*>(static_cast<const void*>(&value)), static_cast<const char*>(static_cast<const void*>(&value)) + sizeof value, bytes);
-  return writeData(bytes, sizeof value);
-}
-
-template<typename T>
-int CRCStream<T>::write(uint32_t base_value, bool is_little_endian) {
-  if (disable_encoding_)
-    is_little_endian = false;
-  const uint32_t value = is_little_endian ? byteSwap(base_value) : base_value;
-  uint8_t bytes[sizeof value];
-  std::copy(static_cast<const char*>(static_cast<const void*>(&value)), static_cast<const char*>(static_cast<const void*>(&value)) + sizeof value, bytes);
-  return writeData(bytes, sizeof value);
-}
-
-template<typename T>
-int CRCStream<T>::write(uint16_t base_value, bool is_little_endian) {
-  if (disable_encoding_)
-    is_little_endian = false;
-  const uint16_t value = is_little_endian == 1 ? byteSwap(base_value) : base_value;
-  uint8_t bytes[sizeof value];
-  std::copy(static_cast<const char*>(static_cast<const void*>(&value)), static_cast<const char*>(static_cast<const void*>(&value)) + sizeof value, bytes);
-  return writeData(bytes, sizeof value);
-}
-
-template<typename T>
-int CRCStream<T>::read(uint64_t &value, bool is_little_endian) {
-  if (disable_encoding_)
-    is_little_endian = false;
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-
-  if (is_little_endian) {
-    value = ((uint64_t) buf[0] << 56) | ((uint64_t) (buf[1] & 255) << 48) | ((uint64_t) (buf[2] & 255) << 40) | ((uint64_t) (buf[3] & 255) << 32) | ((uint64_t) (buf[4] & 255) << 24)
-        | ((uint64_t) (buf[5] & 255) << 16) | ((uint64_t) (buf[6] & 255) << 8) | ((uint64_t) (buf[7] & 255) << 0);
-  } else {
-    value = ((uint64_t) buf[0] << 0) | ((uint64_t) (buf[1] & 255) << 8) | ((uint64_t) (buf[2] & 255) << 16) | ((uint64_t) (buf[3] & 255) << 24) | ((uint64_t) (buf[4] & 255) << 32)
-        | ((uint64_t) (buf[5] & 255) << 40) | ((uint64_t) (buf[6] & 255) << 48) | ((uint64_t) (buf[7] & 255) << 56);
-  }
-  return sizeof(value);
-}
-
-template<typename T>
-int CRCStream<T>::read(uint32_t &value, bool is_little_endian) {
-  if (disable_encoding_)
-    is_little_endian = false;
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-
-  if (is_little_endian) {
-    value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-  } else {
-    value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
+  CRCStream(gsl::not_null<StreamType*> child_stream, uint64_t initial_crc) {
+    child_stream_ = child_stream;
+    crc_ = gsl::narrow<uLong>(initial_crc);
   }
 
-  return sizeof(value);
-}
-
-template<typename T>
-int CRCStream<T>::read(uint16_t &value, bool is_little_endian) {
-  if (disable_encoding_)
-    is_little_endian = false;
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-
-  if (is_little_endian) {
-    value = (buf[0] << 8) | buf[1];
-  } else {
-    value = buf[0] | buf[1] << 8;
+  CRCStream(CRCStream &&stream) noexcept {
+    child_stream_ = utils::exchange(stream.child_stream_, nullptr);
+    crc_ = utils::exchange(stream.crc_, 0);
   }
-  return sizeof(value);
-}
+};
+
 
 }  // namespace io
 }  // namespace minifi
diff --git a/libminifi/include/io/ClientSocket.h b/libminifi/include/io/ClientSocket.h
index 2f161ac..0401101 100644
--- a/libminifi/include/io/ClientSocket.h
+++ b/libminifi/include/io/ClientSocket.h
@@ -93,7 +93,7 @@
    * @param hostname hostname we are connecting to.
    * @param port port we are connecting to.
    */
-  explicit Socket(const std::shared_ptr<SocketContext> &context, std::string hostname, uint16_t port);
+  Socket(const std::shared_ptr<SocketContext> &context, std::string hostname, uint16_t port);
 
   Socket(const Socket&) = delete;
   Socket(Socket&&) noexcept;
@@ -113,14 +113,14 @@
    * Destructor
    */
 
-  virtual ~Socket();
+  ~Socket() override;
 
-  virtual void closeStream();
+  void close() override;
   /**
    * Initializes the socket
    * @return result of the creation operation.
    */
-  virtual int16_t initialize();
+  int initialize() override;
 
   virtual void setInterface(io::NetworkInterface interface) {
     local_network_interface_ = std::move(interface);
@@ -145,24 +145,19 @@
     port_ = port;
   }
 
-  // data stream extensions
+  using BaseStream::write;
+  using BaseStream::read;
+
+  int write(const uint8_t *value, int size) override;
+
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    * @param retrieve_all_bytes determines if we should read all bytes before returning
    */
-  virtual int readData(std::vector<uint8_t> &buf, int buflen) {
-    return readData(buf, buflen, true);
-  }
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   * @param retrieve_all_bytes determines if we should read all bytes before returning
-   */
-  virtual int readData(uint8_t *buf, int buflen) {
-    return readData(buf, buflen, true);
+  int read(uint8_t *buf, int buflen) override {
+    return read(buf, buflen, true);
   }
 
   /**
@@ -171,65 +166,7 @@
    * @param buflen
    * @param retrieve_all_bytes determines if we should read all bytes before returning
    */
-  virtual int readData(std::vector<uint8_t> &buf, int buflen, bool retrieve_all_bytes);
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   * @param retrieve_all_bytes determines if we should read all bytes before returning
-   */
-  virtual int readData(uint8_t *buf, int buflen, bool retrieve_all_bytes);
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
-
-  /**
-   * writes value to stream
-   * @param value value to write
-   * @param size size of value
-   */
-  virtual int writeData(uint8_t *value, int size);
-
-  /**
-   * Writes a system word
-   * @param value value to write
-   */
-  virtual int write(uint64_t value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Writes a uint32_t
-   * @param value value to write
-   */
-  virtual int write(uint32_t value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Writes a system short
-   * @param value value to write
-   */
-  virtual int write(uint16_t value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Reads a system word
-   * @param value value to write
-   */
-  virtual int read(uint64_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Reads a uint32_t
-   * @param value value to write
-   */
-  virtual int read(uint32_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Reads a system short
-   * @param value value to write
-   */
-  virtual int read(uint16_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
+  virtual int read(uint8_t *buf, int buflen, bool retrieve_all_bytes);
 
  protected:
   /**
@@ -243,24 +180,6 @@
   explicit Socket(const std::shared_ptr<SocketContext> &context, std::string hostname, uint16_t port, uint16_t listeners);
 
   /**
-   * Creates a vector and returns the vector using the provided
-   * type name.
-   * @param t incoming object
-   * @returns vector.
-   */
-  template<typename T>
-  std::vector<uint8_t> readBuffer(const T& t);
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read.
-   */
-  template<typename T>
-  int readBuffer(std::vector<uint8_t>& buf, const T& t);
-
-  /**
    * Creates a connection using the addr object
    * @param ignored ignored
    * @param addr The IPv4 address to connect to
diff --git a/libminifi/include/io/DataStream.h b/libminifi/include/io/DataStream.h
deleted file mode 100644
index 071864e..0000000
--- a/libminifi/include/io/DataStream.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LIBMINIFI_INCLUDE_IO_DATASTREAM_H_
-#define LIBMINIFI_INCLUDE_IO_DATASTREAM_H_
-
-#include <iostream>
-#include <cstdint>
-#include <vector>
-#include "EndianCheck.h"
-#include "utils/gsl.h"
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace io {
-/**
- * DataStream defines the mechanism through which
- * binary data will be written to a sink
- *
- * This object is not intended to be thread safe.
- */
-class DataStream {
- public:
-  DataStream() = default;
-  virtual ~DataStream() noexcept = default;
-
-  /**
-   * Constructor
-   **/
-  explicit DataStream(const uint8_t *buf, const int buflen) {
-    writeData(const_cast<uint8_t*>(buf), buflen);
-  }
-
-  virtual short initialize() { // NOLINT
-    buffer.clear();
-    readBuffer = 0;
-    return 0;
-  }
-
-  virtual void seek(uint64_t offset) {
-    readBuffer += gsl::narrow<uint32_t>(offset);
-  }
-
-  virtual void closeStream() { }
-
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  virtual int readData(std::vector<uint8_t> &buf, int buflen);
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  virtual int readData(uint8_t *buf, int buflen);
-
-  /**
-   * writes valiue to buffer
-   * @param value value to write
-   * @param size size of value
-   */
-  virtual int writeData(uint8_t *value, int size);
-
-  /**
-   * Reads a system word
-   * @param value value to write
-   */
-  virtual int read(uint64_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Reads a uint32_t
-   * @param value value to write
-   */
-  virtual int read(uint32_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Reads a system short
-   * @param value value to write
-   */
-  virtual int read(uint16_t &value, bool is_little_endian = EndiannessCheck::IS_LITTLE);
-
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   **/
-  const uint8_t *getBuffer() const {
-    return buffer.data();
-  }
-
-  /**
-   * Retrieve size of data stream
-   * @return size of data stream
-   **/
-  virtual const size_t getSize() const {
-    return buffer.size();
-  }
-
- protected:
-  // All serialization related method and internal buf
-  std::vector<uint8_t> buffer;
-
-  // read offset to buffer
-  uint32_t readBuffer = 0;
-
- private:
-  int doReadData(uint8_t *buf, int buflen) noexcept;
-};
-
-}  // namespace io
-}  // namespace minifi
-}  // namespace nifi
-}  // namespace apache
-}  // namespace org
-#endif  // LIBMINIFI_INCLUDE_IO_DATASTREAM_H_
diff --git a/libminifi/include/io/DescriptorStream.h b/libminifi/include/io/DescriptorStream.h
index e4ec855..a7ea713 100644
--- a/libminifi/include/io/DescriptorStream.h
+++ b/libminifi/include/io/DescriptorStream.h
@@ -25,7 +25,6 @@
 #include <string>
 #include "EndianCheck.h"
 #include "BaseStream.h"
-#include "Serializable.h"
 #include "core/logging/LoggerConfiguration.h"
 
 namespace org {
@@ -49,136 +48,30 @@
    */
   explicit DescriptorStream(int fd);
 
-  ~DescriptorStream() override = default;
-
   /**
    * Skip to the specified offset.
    * @param offset offset to which we will skip
    */
   void seek(uint64_t offset) override;
 
-  const size_t getSize() const override {
-    return -1;
-  }
-
-  // data stream extensions
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * writes value to stream
    * @param value value to write
    * @param size size of value
    */
-  int writeData(uint8_t *value, int size) override;
-
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   */
-  const uint8_t *getBuffer() const {
-    throw std::runtime_error("Stream does not support this operation");
-  }
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t &value) override;
-
-  /**
-   * reads two bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint16_t &base_value, bool is_little_endian = false) override;
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(char &value) override;
-
-  /**
-   * reads a byte array from the stream
-   * @param value reference in which will set the result
-   * @param len length to read
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t *value, int len) override;
-
-  /**
-   * reads four bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint32_t &value, bool is_little_endian = false) override;
-
-  /**
-   * reads eight byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint64_t &value, bool is_little_endian = false) override;
-
-
-  /**
-   * read UTF from stream
-   * @param str reference string
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int readUTF(std::string &str, bool widen = false) override;
-
- protected:
-  /**
-   * Creates a vector and returns the vector using the provided
-   * type name.
-   * @param t incoming object
-   * @returns vector.
-   */
-  template<typename T>
-  std::vector<uint8_t> readBuffer(const T& t);
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read.
-   */
-  template<typename T>
-  int readBuffer(std::vector<uint8_t>& buf, const T& t);
-  std::recursive_mutex file_lock_;
-
-  int fd_;
+  int write(const uint8_t *value, int size) override;
 
  private:
+  std::recursive_mutex file_lock_;
+  int fd_;
+
   std::shared_ptr<logging::Logger> logger_;
 };
 
diff --git a/libminifi/include/io/EndianCheck.h b/libminifi/include/io/EndianCheck.h
index 008a6a4..f4199a6 100644
--- a/libminifi/include/io/EndianCheck.h
+++ b/libminifi/include/io/EndianCheck.h
@@ -35,8 +35,7 @@
     /* do whatever is needed at static init time */
     unsigned int x = 1;
     char *c = reinterpret_cast<char*>(&x);
-    IS_LITTLE = *c == 1;
-    return IS_LITTLE;
+    return *c == 1;
   }
 };
 
diff --git a/libminifi/include/io/FileStream.h b/libminifi/include/io/FileStream.h
index ad7c7aa..54b8d59 100644
--- a/libminifi/include/io/FileStream.h
+++ b/libminifi/include/io/FileStream.h
@@ -55,82 +55,43 @@
   explicit FileStream(const std::string &path, bool append = false);
 
   ~FileStream() override {
-    closeStream();
+    close();
   }
 
-  void closeStream() override;
+  void close() final;
   /**
    * Skip to the specified offset.
    * @param offset offset to which we will skip
    */
   void seek(uint64_t offset) override;
 
-  const size_t getSize() const override {
+  size_t size() const override {
     return length_;
   }
 
-  // data stream extensions
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
+  using BaseStream::read;
+  using BaseStream::write;
 
   /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
+   * Reads data and places it into buf
+   * @param buf buffer in which we extract data
+   * @param buflen
    */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * writes value to stream
    * @param value value to write
    * @param size size of value
    */
-  int writeData(uint8_t *value, int size) override;
+  int write(const uint8_t *value, int size) override;
 
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   **/
-  const uint8_t *getBuffer() const {
-    throw std::runtime_error("Stream does not support this operation");
-  }
-
- protected:
-  /**
-   * Creates a vector and returns the vector using the provided
-   * type name.
-   * @param t incoming object
-   * @returns vector.
-   */
-  template<typename T>
-  std::vector<uint8_t> readBuffer(const T& t);
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read.
-   */
-  template<typename T>
-  int readBuffer(std::vector<uint8_t>& buf, const T& t);
   std::mutex file_lock_;
   std::unique_ptr<std::fstream> file_stream_;
   size_t offset_;
   std::string path_;
   size_t length_;
 
- private:
   std::shared_ptr<logging::Logger> logger_;
 };
 
diff --git a/libminifi/include/io/InputStream.h b/libminifi/include/io/InputStream.h
new file mode 100644
index 0000000..086a6ef
--- /dev/null
+++ b/libminifi/include/io/InputStream.h
@@ -0,0 +1,86 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdexcept>
+#include <vector>
+#include <string>
+#include "Stream.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+class InputStream : public virtual Stream {
+ public:
+  virtual size_t size() const {
+    throw std::runtime_error("Querying size is not supported");
+  }
+  /**
+   * reads a byte array from the stream
+   * @param value reference in which will set the result
+   * @param len length to read
+   * @return resulting read size
+   **/
+  virtual int read(uint8_t *value, int len) = 0;
+
+  int read(std::vector<uint8_t>& buffer, int len);
+
+  /**
+   * read string from stream
+   * @param str reference string
+   * @return resulting read size
+   **/
+  int read(std::string &str, bool widen = false);
+
+  /**
+   * read a bool from stream
+   * @param value reference to the output
+   * @return resulting read size
+   **/
+  int read(bool& value);
+
+  /**
+  * reads sizeof(Integral) bytes from the stream
+  * @param value reference in which will set the result
+  * @return resulting read size
+  **/
+  template<typename Integral, typename = std::enable_if<std::is_unsigned<Integral>::value && !std::is_same<Integral, bool>::value>>
+  int read(Integral& value) {
+    uint8_t buf[sizeof(Integral)]{};
+    if (read(buf, sizeof(Integral)) != sizeof(Integral)) {
+      return -1;
+    }
+
+    value = 0;
+    for (std::size_t byteIdx = 0; byteIdx < sizeof(Integral); ++byteIdx) {
+      value += static_cast<Integral>(buf[byteIdx]) << (8 * (sizeof(Integral) - 1) - 8 * byteIdx);
+    }
+
+    return sizeof(Integral);
+  }
+};
+
+}  // namespace io
+}  // namespace minifi
+}  // namespace nifi
+}  // namespace apache
+}  // namespace org
diff --git a/libminifi/include/io/NonConvertingStream.h b/libminifi/include/io/NonConvertingStream.h
deleted file mode 100644
index 4ad3155..0000000
--- a/libminifi/include/io/NonConvertingStream.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LIBMINIFI_INCLUDE_IO_NONCONVERTINGSTREAM_H_
-#define LIBMINIFI_INCLUDE_IO_NONCONVERTINGSTREAM_H_
-
-#include <string>
-#include <vector>
-#include <iostream>
-#include <cstdint>
-#include "EndianCheck.h"
-#include "BaseStream.h"
-#include "Serializable.h"
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace io {
-
-/**
- * Base Stream. Not intended to be thread safe as it is not intended to be shared
- *
- * Extensions may be thread safe and thus shareable, but that is up to the implementation.
- */
-class NonConvertingStream : public BaseStream  {
- public:
-  NonConvertingStream()
-      : composable_stream_(this) {
-  }
-
-  NonConvertingStream(DataStream *other) // NOLINT
-      : composable_stream_(other) {
-  }
-
-  virtual ~NonConvertingStream() = default;
-  /**
-   * write 4 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  int write(uint32_t base_value, bool is_little_endian = false) override;
-
-  int writeData(uint8_t *value, int size) override;
-
-  void seek(uint64_t offset) override {
-    if (composable_stream_ != this) {
-      composable_stream_->seek(offset);
-    } else {
-      DataStream::seek(offset);
-    }
-  }
-
-  /**
-   * write 2 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  int write(uint16_t base_value, bool is_little_endian = false) override;
-
-  /**
-   * write valueto stream
-   * @param value non encoded value
-   * @param len length of value
-   * @param strema output stream
-   * @return resulting write size
-   **/
-  int write(uint8_t *value, int len) override;
-
-  /**
-   * write 8 bytes to stream
-   * @param base_value non encoded value
-   * @param stream output stream
-   * @param is_little_endian endianness determination
-   * @return resulting write size
-   **/
-  int write(uint64_t base_value, bool is_little_endian = false) override;
-
-  /**
-   * write bool to stream
-   * @param value non encoded value
-   * @return resulting write size
-   **/
-  int write(bool value) override;
-
-  /**
-   * write UTF string to stream
-   * @param str string to write
-   * @return resulting write size
-   **/
-  int writeUTF(std::string str, bool widen = false) override;
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t &value) override;
-
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * reads two bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint16_t &base_value, bool is_little_endian = false) override;
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(char &value) override;
-
-  /**
-   * reads a byte array from the stream
-   * @param value reference in which will set the result
-   * @param len length to read
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t *value, int len) override;
-
-  /**
-   * reads four bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint32_t &value, bool is_little_endian = false) override;
-
-  /**
-   * reads eight byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint64_t &value, bool is_little_endian = false) override;
-
-  const size_t getSize() const override {
-      if (composable_stream_ == this) {
-        return buffer.size();
-      } else {
-        return composable_stream_->getSize();
-      }
-    }
-
-  /**
-   * read UTF from stream
-   * @param str reference string
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int readUTF(std::string &str, bool widen = false) override;
-
- protected:
-  DataStream *composable_stream_;
-};
-
-}  // namespace io
-}  // namespace minifi
-}  // namespace nifi
-}  // namespace apache
-}  // namespace org
-#endif  // LIBMINIFI_INCLUDE_IO_NONCONVERTINGSTREAM_H_
diff --git a/libminifi/include/io/OutputStream.h b/libminifi/include/io/OutputStream.h
new file mode 100644
index 0000000..466ebd0
--- /dev/null
+++ b/libminifi/include/io/OutputStream.h
@@ -0,0 +1,95 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdexcept>
+#include <vector>
+#include <string>
+#include "Stream.h"
+#include "utils/gsl.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+/**
+ * Serializable instances provide base functionality to
+ * write certain objects/primitives to a data stream.
+ *
+ */
+class OutputStream : public virtual Stream {
+ public:
+  /**
+   * write valueto stream
+   * @param value non encoded value
+   * @param len length of value
+   * @return resulting write size
+   **/
+  virtual int write(const uint8_t *value, int len) = 0;
+
+  int write(const std::vector<uint8_t>& buffer, int len);
+
+  /**
+   * write bool to stream
+   * @param value non encoded value
+   * @return resulting write size
+   **/
+  int write(bool value);
+
+  /**
+   * write string to stream
+   * @param str string to write
+   * @return resulting write size
+   **/
+  int write(const std::string& str, bool widen = false);
+
+  /**
+   * write string to stream
+   * @param str string to write
+   * @return resulting write size
+   **/
+  int write(const char* str, bool widen = false);
+
+  /**
+  * writes sizeof(Integral) bytes to the stream
+  * @param value to write
+  * @return resulting write size
+  **/
+  template<typename Integral, typename = std::enable_if<std::is_unsigned<Integral>::value && !std::is_same<Integral, bool>::value>>
+  int write(Integral value) {
+    uint8_t buffer[sizeof(Integral)]{};
+
+    for (std::size_t byteIdx = 0; byteIdx < sizeof(Integral); ++byteIdx) {
+      buffer[byteIdx] = gsl::narrow_cast<uint8_t>(value >> (8*(sizeof(Integral) - 1) - 8*byteIdx));
+    }
+
+    return write(buffer, sizeof(Integral));
+  }
+
+ private:
+  int write_str(const char* str, uint32_t len, bool widen);
+};
+
+}  // namespace io
+}  // namespace minifi
+}  // namespace nifi
+}  // namespace apache
+}  // namespace org
diff --git a/libminifi/include/io/Serializable.h b/libminifi/include/io/Serializable.h
deleted file mode 100644
index 8c77015..0000000
--- a/libminifi/include/io/Serializable.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef LIBMINIFI_INCLUDE_IO_SERIALIZABLE_H_
-#define LIBMINIFI_INCLUDE_IO_SERIALIZABLE_H_
-
-#include <string>
-#include "EndianCheck.h"
-#include "DataStream.h"
-#ifdef WIN32
-#include "Winsock2.h"
-#else
-#include <arpa/inet.h>
-#endif
-
-template<typename Integral, typename std::enable_if<
-    std::is_integral<Integral>::value && (sizeof(Integral) == 2), Integral>::type* = nullptr>
-Integral byteSwap(Integral i) {
-  return htons(i);
-}
-template<typename Integral, typename std::enable_if<
-    std::is_integral<Integral>::value &&(sizeof(Integral) == 4), Integral>::type* = nullptr>
-Integral byteSwap(Integral i) {
-  return htonl(i);
-}
-template<typename Integral, typename std::enable_if<
-    std::is_integral<Integral>::value && (sizeof(Integral) == 8), Integral>::type* = nullptr>
-Integral byteSwap(Integral i) {
-#ifdef htonll
-  return htonll(i);
-#else
-  uint32_t lower_32_bits = static_cast<uint32_t>(i);
-  uint32_t higher_32_bits = static_cast<uint32_t>(i >> 32);
-  return (static_cast<uint64_t>(byteSwap(lower_32_bits)) << 32) + byteSwap(higher_32_bits);
-#endif
-}
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace io {
-
-/**
- * Serializable instances provide base functionality to
- * write certain objects/primitives to a data stream.
- *
- */
-class Serializable {
- public:
-  /**
-   * write byte to stream
-   * @return resulting write size
-   **/
-  int write(uint8_t value, DataStream *stream);
-
-  /**
-   * write byte to stream
-   * @return resulting write size
-   **/
-  int write(char value, DataStream *stream);
-
-  /**
-   * write valueto stream
-   * @param value non encoded value
-   * @param len length of value
-   * @param strema output stream
-   * @return resulting write size
-   **/
-  int write(const uint8_t *value, int len, DataStream *stream);
-
-  /**
-   * write bool to stream
-   * @param value non encoded value
-   * @return resulting write size
-   **/
-  int write(bool value, DataStream *stream);
-
-  /**
-   * write UTF string to stream
-   * @param str string to write
-   * @return resulting write size
-   **/
-  int writeUTF(std::string str, DataStream *stream, bool widen = false);
-
-  /**
-  * writes 2-8 bytes to stream
-  * @param base_value non encoded value
-  * @param stream output stream
-  * @param is_little_endian endianness determination
-  * @return resulting write size
-  **/
-  template<typename Integral, typename std::enable_if<
-      (sizeof(Integral) > 1) &&
-      std::is_integral<Integral>::value &&
-      !std::is_signed<Integral>::value
-      , Integral>::type* = nullptr>
-  int write(Integral const & base_value, DataStream *stream, bool is_little_endian = EndiannessCheck::IS_LITTLE) {
-    const Integral value = is_little_endian ? byteSwap(base_value) : base_value;
-
-    return stream->writeData(reinterpret_cast<uint8_t *>(const_cast<Integral*>(&value)), sizeof(Integral));
-  }
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t &value, DataStream *stream);
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(char &value, DataStream *stream);
-
-  /**
-   * reads a byte array from the stream
-   * @param value reference in which will set the result
-   * @param len length to read
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t *value, int len, DataStream *stream);
-
-  /**
-   * read UTF from stream
-   * @param str reference string
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int readUTF(std::string &str, DataStream *stream, bool widen = false);
-
-  /**
-  * reads 2-8 bytes from the stream
-  * @param value reference in which will set the result
-  * @param stream stream from which we will read
-  * @return resulting read size
-  **/
-  template<typename Integral, typename std::enable_if<
-      (sizeof(Integral) > 1) &&
-      std::is_integral<Integral>::value &&
-      !std::is_signed<Integral>::value
-      , Integral>::type* = nullptr>
-  int read(Integral &value, DataStream *stream, bool is_little_endian = EndiannessCheck::IS_LITTLE) {
-    return stream->read(value, is_little_endian);
-  }
-
- protected:
-};
-
-}  // namespace io
-}  // namespace minifi
-}  // namespace nifi
-}  // namespace apache
-}  // namespace org
-#endif  // LIBMINIFI_INCLUDE_IO_SERIALIZABLE_H_
diff --git a/libminifi/include/io/ServerSocket.h b/libminifi/include/io/ServerSocket.h
index db24afb..1941b2d 100644
--- a/libminifi/include/io/ServerSocket.h
+++ b/libminifi/include/io/ServerSocket.h
@@ -48,19 +48,19 @@
 
   virtual ~ServerSocket();
 
-  virtual int16_t initialize(bool loopbackOnly) {
+  int16_t initialize(bool loopbackOnly) override {
     is_loopback_only_ = loopbackOnly;
     return Socket::initialize();
   }
 
-  virtual int16_t initialize() {
+  int initialize() override {
     return Socket::initialize();
   }
 
   /**
    * Registers a call back and starts the read for the server socket.
    */
-  virtual void registerCallback(std::function<bool()> accept_function, std::function<void(io::BaseStream *)> handler);
+  void registerCallback(std::function<bool()> accept_function, std::function<void(io::BaseStream *)> handler) override;
 
  private:
   void close_fd(int fd);
diff --git a/libminifi/include/io/Stream.h b/libminifi/include/io/Stream.h
new file mode 100644
index 0000000..5b8b2b1
--- /dev/null
+++ b/libminifi/include/io/Stream.h
@@ -0,0 +1,52 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+/**
+ * All streams serialize/deserialize in big-endian
+ */
+class Stream {
+ public:
+  virtual void close() {}
+
+  virtual void seek(uint64_t offset) {
+    throw std::runtime_error("Seek is not supported");
+  }
+
+  virtual int initialize() {
+    return 1;
+  }
+
+  virtual const uint8_t* getBuffer() const {
+    throw std::runtime_error("Not a buffered stream");
+  }
+  virtual ~Stream() = default;
+};
+
+}  // namespace io
+}  // namespace minifi
+}  // namespace nifi
+}  // namespace apache
+}  // namespace org
diff --git a/libminifi/include/io/ZlibStream.h b/libminifi/include/io/ZlibStream.h
index a677dd2..ab4d419 100644
--- a/libminifi/include/io/ZlibStream.h
+++ b/libminifi/include/io/ZlibStream.h
@@ -27,6 +27,7 @@
 
 #include "BaseStream.h"
 #include "core/logging/LoggerConfiguration.h"
+#include "utils/gsl.h"
 
 namespace org {
 namespace apache {
@@ -46,13 +47,12 @@
   FINISHED
 };
 
-class ZlibBaseStream : public BaseStream {
+class ZlibBaseStream : public OutputStream {
  public:
   virtual bool isFinished() const;
 
  protected:
-  ZlibBaseStream();
-  explicit ZlibBaseStream(DataStream* other);
+  explicit ZlibBaseStream(gsl::not_null<OutputStream*> output);
 
   ZlibBaseStream(const ZlibBaseStream&) = delete;
   ZlibBaseStream& operator=(const ZlibBaseStream&) = delete;
@@ -62,12 +62,12 @@
   ZlibStreamState state_{ZlibStreamState::UNINITIALIZED};
   z_stream strm_{};
   std::vector<uint8_t> outputBuffer_;
+  gsl::not_null<OutputStream*> output_;
 };
 
 class ZlibCompressStream : public ZlibBaseStream {
  public:
-  explicit ZlibCompressStream(ZlibCompressionFormat format = ZlibCompressionFormat::GZIP, int level = Z_DEFAULT_COMPRESSION);
-  explicit ZlibCompressStream(DataStream* other, ZlibCompressionFormat format = ZlibCompressionFormat::GZIP, int level = Z_DEFAULT_COMPRESSION);
+  explicit ZlibCompressStream(gsl::not_null<OutputStream*> output, ZlibCompressionFormat format = ZlibCompressionFormat::GZIP, int level = Z_DEFAULT_COMPRESSION);
 
   ZlibCompressStream(const ZlibCompressStream&) = delete;
   ZlibCompressStream& operator=(const ZlibCompressStream&) = delete;
@@ -76,9 +76,9 @@
 
   ~ZlibCompressStream() override;
 
-  int writeData(uint8_t* value, int size) override;
+  int write(const uint8_t* value, int size) override;
 
-  void closeStream() override;
+  void close() override;
 
  private:
   std::shared_ptr<logging::Logger> logger_{logging::LoggerFactory<ZlibCompressStream>::getLogger()};
@@ -86,8 +86,7 @@
 
 class ZlibDecompressStream : public ZlibBaseStream {
  public:
-  explicit ZlibDecompressStream(ZlibCompressionFormat format = ZlibCompressionFormat::GZIP);
-  explicit ZlibDecompressStream(DataStream* other, ZlibCompressionFormat format = ZlibCompressionFormat::GZIP);
+  explicit ZlibDecompressStream(gsl::not_null<OutputStream*> output, ZlibCompressionFormat format = ZlibCompressionFormat::GZIP);
 
   ZlibDecompressStream(const ZlibDecompressStream&) = delete;
   ZlibDecompressStream& operator=(const ZlibDecompressStream&) = delete;
@@ -96,7 +95,7 @@
 
   ~ZlibDecompressStream() override;
 
-  int writeData(uint8_t *value, int size) override;
+  int write(const uint8_t *value, int size) override;
 
  private:
   std::shared_ptr<logging::Logger> logger_{logging::LoggerFactory<ZlibDecompressStream>::getLogger()};
diff --git a/libminifi/include/io/tls/SecureDescriptorStream.h b/libminifi/include/io/tls/SecureDescriptorStream.h
index 1fe3ff1..e213d43 100644
--- a/libminifi/include/io/tls/SecureDescriptorStream.h
+++ b/libminifi/include/io/tls/SecureDescriptorStream.h
@@ -30,7 +30,6 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "io/BaseStream.h"
 #include "io/EndianCheck.h"
-#include "io/Serializable.h"
 
 namespace org {
 namespace apache {
@@ -61,123 +60,25 @@
    */
   void seek(uint64_t offset) override;
 
-  const size_t getSize() const override {
+  size_t size() const override {
     return -1;
   }
 
-  // data stream extensions
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    */
-  int readData(std::vector<uint8_t> &buf, int buflen) override;
-  /**
-   * Reads data and places it into buf
-   * @param buf buffer in which we extract data
-   * @param buflen
-   */
-  int readData(uint8_t *buf, int buflen) override;
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
-   */
-  virtual int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * writes value to stream
    * @param value value to write
    * @param size size of value
    */
-  int writeData(uint8_t *value, int size) override;
-
-  /**
-   * Returns the underlying buffer
-   * @return vector's array
-   */
-  const uint8_t *getBuffer() const {
-    throw std::runtime_error("Stream does not support this operation");
-  }
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t &value) override;
-
-  /**
-   * reads two bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint16_t &base_value, bool is_little_endian = false) override;
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(char &value) override;
-
-  /**
-   * reads a byte array from the stream
-   * @param value reference in which will set the result
-   * @param len length to read
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint8_t *value, int len) override;
-
-  /**
-   * reads four bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint32_t &value, bool is_little_endian = false) override;
-
-  /**
-   * reads eight byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int read(uint64_t &value, bool is_little_endian = false) override;
-
-
-  /**
-   * read UTF from stream
-   * @param str reference string
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  int readUTF(std::string &str, bool widen = false) override;
+  int write(const uint8_t *value, int size) override;
 
  protected:
-  /**
-   * Creates a vector and returns the vector using the provided
-   * type name.
-   * @param t incoming object
-   * @returns vector.
-   */
-  template<typename T>
-  std::vector<uint8_t> readBuffer(const T& t);
-
-  /**
-   * Populates the vector using the provided type name.
-   * @param buf output buffer
-   * @param t incoming object
-   * @returns number of bytes read.
-   */
-  template<typename T>
-  int readBuffer(std::vector<uint8_t>& buf, const T& t);
   std::recursive_mutex file_lock_;
 
   int fd_;
diff --git a/libminifi/include/io/tls/TLSServerSocket.h b/libminifi/include/io/tls/TLSServerSocket.h
index 6f4d960..f5bfc2b 100644
--- a/libminifi/include/io/tls/TLSServerSocket.h
+++ b/libminifi/include/io/tls/TLSServerSocket.h
@@ -41,12 +41,12 @@
 
   virtual ~TLSServerSocket();
 
-  int16_t initialize(bool loopbackOnly) {
+  int16_t initialize(bool loopbackOnly) override {
     is_loopback_only_ = loopbackOnly;
     return TLSSocket::initialize();
   }
 
-  virtual int16_t initialize() {
+  int initialize() override {
     return TLSSocket::initialize();
   }
 
@@ -59,7 +59,7 @@
    * Initializes the socket
    * @return result of the creation operation.
    */
-  virtual void registerCallback(std::function<bool()> accept_function, std::function<void(io::BaseStream *)> handler);
+  void registerCallback(std::function<bool()> accept_function, std::function<void(io::BaseStream *)> handler) override;
 
  private:
   std::function<void(std::function<bool()> accept_function, std::function<int(std::vector<uint8_t>*, int *)> handler)> fx;
diff --git a/libminifi/include/io/tls/TLSSocket.h b/libminifi/include/io/tls/TLSSocket.h
index 8b4bd5c..6bf741d 100644
--- a/libminifi/include/io/tls/TLSSocket.h
+++ b/libminifi/include/io/tls/TLSSocket.h
@@ -114,13 +114,13 @@
 
   TLSSocket& operator=(TLSSocket&&);
 
-  virtual ~TLSSocket();
+  ~TLSSocket() override;
 
   /**
    * Initializes the socket
    * @return result of the creation operation.
    */
-  int16_t initialize() {
+  int initialize() override {
     return initialize(true);
   }
 
@@ -131,28 +131,19 @@
    * @param msec timeout interval to wait
    * @returns file descriptor
    */
-  virtual int16_t select_descriptor(uint16_t msec);
+  int16_t select_descriptor(uint16_t msec) override;
 
-  virtual int readData(std::vector<uint8_t> &buf, int buflen);
+  using Socket::read;
+  using Socket::write;
 
-  virtual int readData(uint8_t *buf, int buflen, bool retrieve_all_bytes);
-
-  virtual int readData(std::vector<uint8_t> &buf, int buflen, bool retrieve_all_bytes);
+  int read(uint8_t *buf, int buflen, bool retrieve_all_bytes) override;
 
   /**
    * Reads data and places it into buf
    * @param buf buffer in which we extract data
    * @param buflen
    */
-  virtual int readData(uint8_t *buf, int buflen);
-
-  /**
-   * Write value to the stream using std::vector
-   * @param buf incoming buffer
-   * @param buflen buffer to write
-   *
-   */
-  int writeData(std::vector<uint8_t> &buf, int buflen);
+  int read(uint8_t *buf, int buflen) override;
 
   /**
    * Write value to the stream using uint8_t ptr
@@ -160,12 +151,12 @@
    * @param buflen buffer to write
    *
    */
-  int writeData(uint8_t *value, int size);
+  int write(const uint8_t *value, int size) override;
 
-  void closeStream();  // override
+  void close() override;
 
  protected:
-  int writeData(uint8_t *value, int size, int fd);
+  int writeData(const uint8_t *value, unsigned int size, int fd);
 
   SSL *get_ssl(int fd) {
     if (UNLIKELY(listeners_ > 0)) {
diff --git a/libminifi/include/provenance/Provenance.h b/libminifi/include/provenance/Provenance.h
index 41670e7..14ef965 100644
--- a/libminifi/include/provenance/Provenance.h
+++ b/libminifi/include/provenance/Provenance.h
@@ -37,7 +37,6 @@
 #include "FlowFileRecord.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "ResourceClaim.h"
-#include "io/Serializable.h"
 #include "utils/Id.h"
 #include "utils/TimeUtil.h"
 
@@ -350,39 +349,39 @@
   using SerializableComponent::Serialize;
 
   // Serialize the event to a stream
-  bool Serialize(org::apache::nifi::minifi::io::DataStream& outStream);
+  bool Serialize(org::apache::nifi::minifi::io::BufferStream& outStream);
 
   // Serialize and Persistent to the repository
   bool Serialize(const std::shared_ptr<core::SerializableComponent> &repo);
   // DeSerialize
   bool DeSerialize(const uint8_t *buffer, const size_t bufferSize);
   // DeSerialize
-  bool DeSerialize(org::apache::nifi::minifi::io::DataStream &stream) {
-    return DeSerialize(stream.getBuffer(), stream.getSize());
+  bool DeSerialize(org::apache::nifi::minifi::io::BufferStream &stream) {
+    return DeSerialize(stream.getBuffer(), stream.size());
   }
   // DeSerialize
   bool DeSerialize(const std::shared_ptr<core::SerializableComponent> &repo);
 
   uint64_t getEventTime(const uint8_t *buffer, const size_t bufferSize) {
     int size = bufferSize > 72 ? 72 : bufferSize;
-    org::apache::nifi::minifi::io::DataStream outStream(buffer, size);
+    org::apache::nifi::minifi::io::BufferStream outStream(buffer, size);
 
     std::string uuid;
-    int ret = readUTF(uuid, &outStream);
+    int ret = outStream.read(uuid);
 
     if (ret <= 0) {
       return 0;
     }
 
     uint32_t eventType;
-    ret = read(eventType, &outStream);
+    ret = outStream.read(eventType);
     if (ret != 4) {
       return 0;
     }
 
     uint64_t event_time;
 
-    ret = read(event_time, &outStream);
+    ret = outStream.read(event_time);
     if (ret != 8) {
       return 0;
     }
diff --git a/libminifi/include/sitetosite/Peer.h b/libminifi/include/sitetosite/Peer.h
index b9b243f..7935acb 100644
--- a/libminifi/include/sitetosite/Peer.h
+++ b/libminifi/include/sitetosite/Peer.h
@@ -32,7 +32,7 @@
 #include "core/Property.h"
 #include "io/BaseStream.h"
 #include "io/ClientSocket.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "io/EndianCheck.h"
 #include "properties/Configure.h"
 #include "utils/HTTPClient.h"
@@ -145,7 +145,7 @@
   /*
    * Create a new site2site peer
    */
-  explicit SiteToSitePeer(std::unique_ptr<org::apache::nifi::minifi::io::DataStream> injected_socket, const std::string host, uint16_t port, const std::string &ifc)
+  explicit SiteToSitePeer(std::unique_ptr<org::apache::nifi::minifi::io::BaseStream> injected_socket, const std::string host, uint16_t port, const std::string &ifc)
       : SiteToSitePeer(host, port, ifc) {
     stream_ = std::move(injected_socket);
   }
@@ -280,62 +280,27 @@
     return this->proxy_;
   }
 
-  void setStream(std::unique_ptr<org::apache::nifi::minifi::io::DataStream> stream) {
+  void setStream(std::unique_ptr<org::apache::nifi::minifi::io::BaseStream> stream) {
     stream_ = nullptr;
     if (stream)
       stream_ = std::move(stream);
   }
 
-  org::apache::nifi::minifi::io::DataStream *getStream() {
+  org::apache::nifi::minifi::io::BaseStream *getStream() {
     return stream_.get();
   }
 
-  int write(uint8_t value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::write(value, stream_.get());
+  using BaseStream::write;
+  using BaseStream::read;
+
+  int write(const uint8_t* data, int len) override {
+    return stream_->write(data, len);
   }
-  int write(char value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::write(value, stream_.get());
+
+  int read(uint8_t* data, int len) override {
+    return stream_->read(data, len);
   }
-  int write(uint32_t value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::write(value, stream_.get());
-  }
-  int write(uint16_t value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::write(value, stream_.get());
-  }
-  int write(uint8_t *value, int len) {
-    return Serializable::write(value, len, stream_.get());
-  }
-  int write(uint64_t value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::write(value, stream_.get());
-  }
-  int write(bool value) {
-    uint8_t temp = value;
-    return Serializable::write(temp, stream_.get());
-  }
-  int writeUTF(std::string str, bool widen = false) {
-    return Serializable::writeUTF(str, stream_.get(), widen);
-  }
-  int read(uint8_t &value) {
-    return Serializable::read(value, stream_.get());
-  }
-  int read(uint16_t &value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::read(value, stream_.get());
-  }
-  int read(char &value) {
-    return Serializable::read(value, stream_.get());
-  }
-  int read(uint8_t *value, int len) {
-    return Serializable::read(value, len, stream_.get());
-  }
-  int read(uint32_t &value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::read(value, stream_.get());
-  }
-  int read(uint64_t &value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    return Serializable::read(value, stream_.get());
-  }
-  int readUTF(std::string &str, bool widen = false) {
-    return org::apache::nifi::minifi::io::Serializable::readUTF(str, stream_.get(), widen);
-  }
+
   // open connection to the peer
   bool Open();
   // close connection to the peer
@@ -345,7 +310,10 @@
    * Move assignment operator.
    */
   SiteToSitePeer& operator=(SiteToSitePeer&& other) {
-    stream_ = std::unique_ptr<org::apache::nifi::minifi::io::DataStream>(other.stream_.release());
+    if (this == &other) {
+      return *this;
+    }
+    stream_ = std::move(other.stream_);
     host_ = std::move(other.host_);
     port_ = std::move(other.port_);
     local_network_interface_ = std::move(other.local_network_interface_);
@@ -360,7 +328,7 @@
   SiteToSitePeer &operator=(const SiteToSitePeer &parent) = delete;
 
  private:
-  std::unique_ptr<org::apache::nifi::minifi::io::DataStream> stream_;
+  std::unique_ptr<org::apache::nifi::minifi::io::BaseStream> stream_;
 
   std::string host_;
 
diff --git a/libminifi/include/sitetosite/SiteToSite.h b/libminifi/include/sitetosite/SiteToSite.h
index 43dcccd..741f48f 100644
--- a/libminifi/include/sitetosite/SiteToSite.h
+++ b/libminifi/include/sitetosite/SiteToSite.h
@@ -236,7 +236,7 @@
   /*!
    * Create a new transaction
    */
-  explicit Transaction(TransferDirection direction, org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> &stream)
+  explicit Transaction(TransferDirection direction, org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> &&stream)
       : closed_(false),
         crcStream(std::move(stream)) {
     _state = TRANSACTION_STARTED;
diff --git a/libminifi/include/sitetosite/SiteToSiteClient.h b/libminifi/include/sitetosite/SiteToSiteClient.h
index bbf08ec..9afb016 100644
--- a/libminifi/include/sitetosite/SiteToSiteClient.h
+++ b/libminifi/include/sitetosite/SiteToSiteClient.h
@@ -296,7 +296,7 @@
     uint64_t total = 0;
     while (len > 0) {
       int size = len < 16384 ? static_cast<int>(len) : 16384;
-      int ret = _packet->transaction_->getStream().readData(buffer, size);
+      int ret = _packet->transaction_->getStream().read(buffer, size);
       if (ret != size) {
         logging::LOG_ERROR(_packet->logger_reference_) << "Site2Site Receive Flow Size " << size << " Failed " << ret << ", should have received " << len;
         return -1;
@@ -330,13 +330,13 @@
       if (readSize < 0) {
         return -1;
       }
-      int ret = _packet->transaction_->getStream().writeData(buffer, readSize);
+      int ret = _packet->transaction_->getStream().write(buffer, readSize);
       if (ret != readSize) {
         logging::LOG_INFO(_packet->logger_reference_) << "Site2Site Send Flow Size " << readSize << " Failed " << ret;
         return -1;
       }
       size += readSize;
-    } while (size < stream->getSize());
+    } while (size < stream->size());
     _packet->_size = size;
     return size;
   }
diff --git a/libminifi/include/sitetosite/SiteToSiteFactory.h b/libminifi/include/sitetosite/SiteToSiteFactory.h
index 0f8fa76..f37e864 100644
--- a/libminifi/include/sitetosite/SiteToSiteFactory.h
+++ b/libminifi/include/sitetosite/SiteToSiteFactory.h
@@ -38,13 +38,11 @@
  * @returns SiteToSitePeer
  */
 static std::unique_ptr<SiteToSitePeer> createStreamingPeer(const SiteToSiteClientConfiguration &client_configuration) {
-  std::unique_ptr<org::apache::nifi::minifi::io::DataStream> str = nullptr;
+  std::unique_ptr<org::apache::nifi::minifi::io::BaseStream> str = nullptr;
   if (nullptr != client_configuration.getSecurityContext()) {
-    str = std::unique_ptr<org::apache::nifi::minifi::io::DataStream>(
-        client_configuration.getStreamFactory()->createSecureSocket(client_configuration.getPeer()->getHost(), client_configuration.getPeer()->getPort(), client_configuration.getSecurityContext()));
+    str = client_configuration.getStreamFactory()->createSecureSocket(client_configuration.getPeer()->getHost(), client_configuration.getPeer()->getPort(), client_configuration.getSecurityContext());
   } else {
-    str = std::unique_ptr<org::apache::nifi::minifi::io::DataStream>(
-        client_configuration.getStreamFactory()->createSocket(client_configuration.getPeer()->getHost(), client_configuration.getPeer()->getPort()));
+    str = client_configuration.getStreamFactory()->createSocket(client_configuration.getPeer()->getHost(), client_configuration.getPeer()->getPort());
   }
 
   if (nullptr == str)
diff --git a/libminifi/include/utils/ByteArrayCallback.h b/libminifi/include/utils/ByteArrayCallback.h
index 1595158..1639bf9 100644
--- a/libminifi/include/utils/ByteArrayCallback.h
+++ b/libminifi/include/utils/ByteArrayCallback.h
@@ -45,10 +45,10 @@
   virtual int64_t process(std::shared_ptr<io::BaseStream> stream) {
     stream->seek(0);
 
-    if (stream->getSize() > 0) {
-      vec.resize(stream->getSize());
+    if (stream->size() > 0) {
+      vec.resize(stream->size());
 
-      stream->readData(reinterpret_cast<uint8_t*>(vec.data()), gsl::narrow<int>(stream->getSize()));
+      stream->read(reinterpret_cast<uint8_t*>(vec.data()), gsl::narrow<int>(stream->size()));
     }
 
     ptr = reinterpret_cast<char*>(&vec[0]);
diff --git a/libminifi/src/FlowFileRecord.cpp b/libminifi/src/FlowFileRecord.cpp
index 882686c..a1976ef 100644
--- a/libminifi/src/FlowFileRecord.cpp
+++ b/libminifi/src/FlowFileRecord.cpp
@@ -174,75 +174,75 @@
     logger_->log_error("NiFi FlowFile Store event %s can not found", key);
     return false;
   }
-  io::DataStream stream((const uint8_t*) value.data(), value.length());
+  io::BufferStream stream((const uint8_t*) value.data(), value.length());
 
   ret = DeSerialize(stream);
 
   if (ret) {
-    logger_->log_debug("NiFi FlowFile retrieve uuid %s size %llu connection %s success", uuidStr_, stream.getSize(), uuid_connection_);
+    logger_->log_debug("NiFi FlowFile retrieve uuid %s size %llu connection %s success", uuidStr_, stream.size(), uuid_connection_);
   } else {
-    logger_->log_debug("NiFi FlowFile retrieve uuid %s size %llu connection %s fail", uuidStr_, stream.getSize(), uuid_connection_);
+    logger_->log_debug("NiFi FlowFile retrieve uuid %s size %llu connection %s fail", uuidStr_, stream.size(), uuid_connection_);
   }
 
   return ret;
 }
 
-bool FlowFileRecord::Serialize(io::DataStream &outStream) {
+bool FlowFileRecord::Serialize(io::BufferStream &outStream) {
   int ret;
 
-  ret = write(this->event_time_, &outStream);
+  ret = outStream.write(this->event_time_);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->entry_date_, &outStream);
+  ret = outStream.write(this->entry_date_);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->lineage_start_date_, &outStream);
+  ret = outStream.write(this->lineage_start_date_);
   if (ret != 8) {
     return false;
   }
 
-  ret = writeUTF(this->uuidStr_, &outStream);
+  ret = outStream.write(this->uuidStr_);
   if (ret <= 0) {
     return false;
   }
 
-  ret = writeUTF(this->uuid_connection_, &outStream);
+  ret = outStream.write(this->uuid_connection_);
   if (ret <= 0) {
     return false;
   }
   // write flow attributes
   uint32_t numAttributes = this->attributes_.size();
-  ret = write(numAttributes, &outStream);
+  ret = outStream.write(numAttributes);
   if (ret != 4) {
     return false;
   }
 
   for (auto& itAttribute : attributes_) {
-    ret = writeUTF(itAttribute.first, &outStream, true);
+    ret = outStream.write(itAttribute.first, true);
     if (ret <= 0) {
       return false;
     }
-    ret = writeUTF(itAttribute.second, &outStream, true);
+    ret = outStream.write(itAttribute.second, true);
     if (ret <= 0) {
       return false;
     }
   }
 
-  ret = writeUTF(this->getContentFullPath(), &outStream);
+  ret = outStream.write(this->getContentFullPath());
   if (ret <= 0) {
     return false;
   }
 
-  ret = write(this->size_, &outStream);
+  ret = outStream.write(this->size_);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->offset_, &outStream);
+  ret = outStream.write(this->offset_);
   if (ret != 8) {
     return false;
   }
@@ -255,19 +255,19 @@
     return true;
   }
 
-  io::DataStream outStream;
+  io::BufferStream outStream;
 
   if (!Serialize(outStream)) {
     return false;
   }
 
-  if (flow_repository_->Put(uuidStr_, const_cast<uint8_t*>(outStream.getBuffer()), outStream.getSize())) {
-    logger_->log_debug("NiFi FlowFile Store event %s size %llu success", uuidStr_, outStream.getSize());
+  if (flow_repository_->Put(uuidStr_, const_cast<uint8_t*>(outStream.getBuffer()), outStream.size())) {
+    logger_->log_debug("NiFi FlowFile Store event %s size %llu success", uuidStr_, outStream.size());
     // on behalf of the persisted record instance
     if (claim_) claim_->increaseFlowFileRecordOwnedCount();
     return true;
   } else {
-    logger_->log_error("NiFi FlowFile Store event %s size %llu fail", uuidStr_, outStream.getSize());
+    logger_->log_error("NiFi FlowFile Store event %s size %llu fail", uuidStr_, outStream.size());
     return false;
   }
 
@@ -275,69 +275,56 @@
 }
 
 bool FlowFileRecord::DeSerialize(const uint8_t *buffer, const int bufferSize) {
-  int ret;
+  io::BufferStream outStream(buffer, bufferSize);
 
-  io::DataStream outStream(buffer, bufferSize);
-
-  ret = read(this->event_time_, &outStream);
-  if (ret != 8) {
+  if (outStream.read(event_time_) != sizeof(event_time_)) {
     return false;
   }
 
-  ret = read(this->entry_date_, &outStream);
-  if (ret != 8) {
+  if (outStream.read(entry_date_) != sizeof(entry_date_)) {
     return false;
   }
 
-  ret = read(this->lineage_start_date_, &outStream);
-  if (ret != 8) {
+  if (outStream.read(lineage_start_date_) != sizeof(lineage_start_date_)) {
     return false;
   }
 
-  ret = readUTF(this->uuidStr_, &outStream);
-  if (ret <= 0) {
+  if (outStream.read(uuidStr_) <= 0) {
     return false;
   }
 
-  ret = readUTF(this->uuid_connection_, &outStream);
-  if (ret <= 0) {
+  if (outStream.read(uuid_connection_) <= 0) {
     return false;
   }
 
   // read flow attributes
   uint32_t numAttributes = 0;
-  ret = read(numAttributes, &outStream);
-  if (ret != 4) {
+  if (outStream.read(numAttributes) != sizeof(numAttributes)) {
     return false;
   }
 
   for (uint32_t i = 0; i < numAttributes; i++) {
     std::string key;
-    ret = readUTF(key, &outStream, true);
-    if (ret <= 0) {
+    if (outStream.read(key, true) <= 0) {
       return false;
     }
     std::string value;
-    ret = readUTF(value, &outStream, true);
-    if (ret <= 0) {
+    if (outStream.read(value, true) <= 0) {
       return false;
     }
     this->attributes_[key] = value;
   }
 
   std::string content_full_path;
-  ret = readUTF(content_full_path, &outStream);
-  if (ret <= 0) {
+  if (outStream.read(content_full_path) <= 0) {
     return false;
   }
 
-  ret = read(this->size_, &outStream);
-  if (ret != 8) {
+  if (outStream.read(size_) != sizeof(size_)) {
     return false;
   }
 
-  ret = read(this->offset_, &outStream);
-  if (ret != 8) {
+  if (outStream.read(offset_) != sizeof(offset_)) {
     return false;
   }
 
diff --git a/libminifi/src/c2/ControllerSocketProtocol.cpp b/libminifi/src/c2/ControllerSocketProtocol.cpp
index 124490f..dd6464d 100644
--- a/libminifi/src/c2/ControllerSocketProtocol.cpp
+++ b/libminifi/src/c2/ControllerSocketProtocol.cpp
@@ -100,7 +100,7 @@
         case Operation::START:
         {
           std::string componentStr;
-          int size = stream->readUTF(componentStr);
+          int size = stream->read(componentStr);
           if ( size != -1 ) {
             auto components = update_sink_->getComponents(componentStr);
             for (const auto& component : components) {
@@ -114,7 +114,7 @@
         case Operation::STOP:
         {
           std::string componentStr;
-          int size = stream->readUTF(componentStr);
+          int size = stream->read(componentStr);
           if ( size != -1 ) {
             auto components = update_sink_->getComponents(componentStr);
             for (const auto& component : components) {
@@ -128,7 +128,7 @@
         case Operation::CLEAR:
         {
           std::string connection;
-          int size = stream->readUTF(connection);
+          int size = stream->read(connection);
           if ( size != -1 ) {
             update_sink_->clearConnection(connection);
           }
@@ -137,14 +137,14 @@
         case Operation::UPDATE:
         {
           std::string what;
-          int size = stream->readUTF(what);
+          int size = stream->read(what);
           if (size == -1) {
             logger_->log_debug("Connection broke");
             break;
           }
           if (what == "flow") {
             std::string ff_loc;
-            int size = stream->readUTF(ff_loc);
+            int size = stream->read(ff_loc);
             std::ifstream tf(ff_loc);
             std::string configuration((std::istreambuf_iterator<char>(tf)),
                 std::istreambuf_iterator<char>());
@@ -159,14 +159,14 @@
         case Operation::DESCRIBE:
         {
           std::string what;
-          int size = stream->readUTF(what);
+          int size = stream->read(what);
           if (size == -1) {
             logger_->log_debug("Connection broke");
             break;
           }
           if (what == "queue") {
             std::string connection;
-            int size = stream->readUTF(connection);
+            int size = stream->read(connection);
             if (size == -1) {
               logger_->log_debug("Connection broke");
               break;
@@ -176,45 +176,45 @@
               std::lock_guard<std::mutex> lock(controller_mutex_);
               response << queue_size_[connection] << " / " << queue_max_[connection];
             }
-            io::BaseStream resp;
-            resp.writeData(&head, 1);
-            resp.writeUTF(response.str());
-            stream->writeData(const_cast<uint8_t*>(resp.getBuffer()), resp.getSize());
+            io::BufferStream resp;
+            resp.write(&head, 1);
+            resp.write(response.str());
+            stream->write(const_cast<uint8_t*>(resp.getBuffer()), resp.size());
           } else if (what == "components") {
-            io::BaseStream resp;
-            resp.writeData(&head, 1);
+            io::BufferStream resp;
+            resp.write(&head, 1);
             uint16_t size = gsl::narrow<uint16_t>(update_sink_->getAllComponents().size());
             resp.write(size);
             for (const auto &component : update_sink_->getAllComponents()) {
-              resp.writeUTF(component->getComponentName());
-              resp.writeUTF(component->isRunning() ? "true" : "false");
+              resp.write(component->getComponentName());
+              resp.write(component->isRunning() ? "true" : "false");
             }
-            stream->writeData(const_cast<uint8_t*>(resp.getBuffer()), resp.getSize());
+            stream->write(const_cast<uint8_t*>(resp.getBuffer()), resp.size());
           } else if (what == "jstack") {
-            io::BaseStream resp;
-            resp.writeData(&head, 1);
+            io::BufferStream resp;
+            resp.write(&head, 1);
             auto traces = update_sink_->getTraces();
             uint64_t trace_size = traces.size();
             resp.write(trace_size);
             for (const auto &trace : traces) {
               const auto &lines = trace.getTraces();
-              resp.writeUTF(trace.getName());
+              resp.write(trace.getName());
               uint64_t lsize = lines.size();
               resp.write(lsize);
               for (const auto &line : lines) {
-                resp.writeUTF(line);
+                resp.write(line);
               }
             }
-            stream->writeData(const_cast<uint8_t*>(resp.getBuffer()), resp.getSize());
+            stream->write(const_cast<uint8_t*>(resp.getBuffer()), resp.size());
           } else if (what == "connections") {
-            io::BaseStream resp;
-            resp.writeData(&head, 1);
+            io::BufferStream resp;
+            resp.write(&head, 1);
             uint16_t size = gsl::narrow<uint16_t>(queue_full_.size());
             resp.write(size);
             for (const auto &connection : queue_full_) {
-              resp.writeUTF(connection.first, false);
+              resp.write(connection.first, false);
             }
-            stream->writeData(const_cast<uint8_t*>(resp.getBuffer()), resp.getSize());
+            stream->write(const_cast<uint8_t*>(resp.getBuffer()), resp.size());
           } else if (what == "getfull") {
             std::vector<std::string> full_connections;
             {
@@ -225,14 +225,14 @@
                 }
               }
             }
-            io::BaseStream resp;
-            resp.writeData(&head, 1);
+            io::BufferStream resp;
+            resp.write(&head, 1);
             uint16_t full_connection_count = gsl::narrow<uint16_t>(full_connections.size());
             resp.write(full_connection_count);
             for (auto conn : full_connections) {
-              resp.writeUTF(conn);
+              resp.write(conn);
             }
-            stream->writeData(const_cast<uint8_t*>(resp.getBuffer()), resp.getSize());
+            stream->write(const_cast<uint8_t*>(resp.getBuffer()), resp.size());
           }
         }
         break;
diff --git a/libminifi/src/core/ContentSession.cpp b/libminifi/src/core/ContentSession.cpp
index f5934f9..8d761d3 100644
--- a/libminifi/src/core/ContentSession.cpp
+++ b/libminifi/src/core/ContentSession.cpp
@@ -33,7 +33,7 @@
 
 std::shared_ptr<ResourceClaim> ContentSession::create() {
   std::shared_ptr<ResourceClaim> claim = std::make_shared<ResourceClaim>(repository_);
-  managedResources_[claim] = std::make_shared<io::BaseStream>();
+  managedResources_[claim] = std::make_shared<io::BufferStream>();
   return claim;
 }
 
@@ -45,12 +45,12 @@
     }
     auto& extension = extendedResources_[resourceId];
     if (!extension) {
-      extension = std::make_shared<io::BaseStream>();
+      extension = std::make_shared<io::BufferStream>();
     }
     return extension;
   }
   if (mode == WriteMode::OVERWRITE) {
-    it->second = std::make_shared<io::BaseStream>();
+    it->second = std::make_shared<io::BufferStream>();
   }
   return it->second;
 }
@@ -71,7 +71,7 @@
     if (outStream == nullptr) {
       throw Exception(REPOSITORY_EXCEPTION, "Couldn't open the underlying resource for write: " + resource.first->getContentFullPath());
     }
-    const auto size = resource.second->getSize();
+    const auto size = resource.second->size();
     if (outStream->write(const_cast<uint8_t*>(resource.second->getBuffer()), size) != size) {
       throw Exception(REPOSITORY_EXCEPTION, "Failed to write new resource: " + resource.first->getContentFullPath());
     }
@@ -81,7 +81,7 @@
     if (outStream == nullptr) {
       throw Exception(REPOSITORY_EXCEPTION, "Couldn't open the underlying resource for append: " + resource.first->getContentFullPath());
     }
-    const auto size = resource.second->getSize();
+    const auto size = resource.second->size();
     if (outStream->write(const_cast<uint8_t*>(resource.second->getBuffer()), size) != size) {
       throw Exception(REPOSITORY_EXCEPTION, "Failed to append to resource: " + resource.first->getContentFullPath());
     }
diff --git a/libminifi/src/core/ProcessSession.cpp b/libminifi/src/core/ProcessSession.cpp
index 20cc9ea..6fcab0c 100644
--- a/libminifi/src/core/ProcessSession.cpp
+++ b/libminifi/src/core/ProcessSession.cpp
@@ -254,11 +254,11 @@
       throw Exception(FILE_OPERATION_EXCEPTION, "Failed to process flowfile content");
     }
 
-    flow->setSize(stream->getSize());
+    flow->setSize(stream->size());
     flow->setOffset(0);
     flow->setResourceClaim(claim);
 
-    stream->closeStream();
+    stream->close();
     std::string details = process_context_->getProcessorNode()->getName() + " modify flow record content " + flow->getUUIDStr();
     uint64_t endTime = utils::timeutils::getTimeMillis();
     provenance_report_->modifyContent(flow, details, endTime - startTime);
@@ -286,14 +286,14 @@
     }
     // Call the callback to write the content
 
-    size_t oldPos = stream->getSize();
+    size_t oldPos = stream->size();
     // this prevents an issue if we write, above, with zero length.
     if (oldPos > 0)
       stream->seek(oldPos + 1);
     if (callback->process(stream) < 0) {
       throw Exception(FILE_OPERATION_EXCEPTION, "Failed to process flowfile content");
     }
-    flow->setSize(stream->getSize());
+    flow->setSize(stream->size());
 
     std::stringstream details;
     details << process_context_->getProcessorNode()->getName() << " modify flow record content " << flow->getUUIDStr();
@@ -349,7 +349,7 @@
  * @param flow flow file
  *
  */
-void ProcessSession::importFrom(io::DataStream &stream, const std::shared_ptr<core::FlowFile> &flow) {
+void ProcessSession::importFrom(io::InputStream &stream, const std::shared_ptr<core::FlowFile> &flow) {
   std::shared_ptr<ResourceClaim> claim = content_session_->create();
   size_t max_read = getpagesize();
   std::vector<uint8_t> charBuffer(max_read);
@@ -362,24 +362,24 @@
       throw Exception(FILE_OPERATION_EXCEPTION, "Could not obtain claim for " + claim->getContentFullPath());
     }
     size_t position = 0;
-    const size_t max_size = stream.getSize();
+    const size_t max_size = stream.size();
     while (position < max_size) {
       const size_t read_size = (std::min)(max_read, max_size - position);
-      stream.readData(charBuffer, read_size);
+      stream.read(charBuffer, read_size);
 
       content_stream->write(charBuffer.data(), read_size);
       position += read_size;
     }
     // Open the source file and stream to the flow file
 
-    flow->setSize(content_stream->getSize());
+    flow->setSize(content_stream->size());
     flow->setOffset(0);
     flow->setResourceClaim(claim);
 
     logger_->log_debug("Import offset %" PRIu64 " length %" PRIu64 " into content %s for FlowFile UUID %s",
         flow->getOffset(), flow->getSize(), flow->getResourceClaim()->getContentFullPath(), flow->getUUIDStr());
 
-    content_stream->closeStream();
+    content_stream->close();
     std::stringstream details;
     details << process_context_->getProcessorNode()->getName() << " modify flow record content " << flow->getUUIDStr();
     auto endTime = utils::timeutils::getTimeMillis();
@@ -433,14 +433,14 @@
       }
 
       if (!invalidWrite) {
-        flow->setSize(stream->getSize());
+        flow->setSize(stream->size());
         flow->setOffset(0);
         flow->setResourceClaim(claim);
 
         logger_->log_debug("Import offset %" PRIu64 " length %" PRIu64 " into content %s for FlowFile UUID %s", flow->getOffset(), flow->getSize(), flow->getResourceClaim()->getContentFullPath(),
                            flow->getUUIDStr());
 
-        stream->closeStream();
+        stream->close();
         input.close();
         if (!keepSource)
           std::remove(source.c_str());
@@ -449,7 +449,7 @@
         auto endTime = utils::timeutils::getTimeMillis();
         provenance_report_->modifyContent(flow, details.str(), endTime - startTime);
       } else {
-        stream->closeStream();
+        stream->close();
         input.close();
         throw Exception(FILE_OPERATION_EXCEPTION, "File Import Error");
       }
@@ -528,7 +528,7 @@
         }
         if (stream->write(begin, len) != len) {
           logger_->log_error("Error while writing");
-          stream->closeStream();
+          stream->close();
           throw Exception(FILE_OPERATION_EXCEPTION, "File Export Error creating Flowfile");
         }
 
@@ -537,12 +537,12 @@
           break;
         }
         flowFile = std::static_pointer_cast<FlowFileRecord>(create());
-        flowFile->setSize(stream->getSize());
+        flowFile->setSize(stream->size());
         flowFile->setOffset(0);
         flowFile->setResourceClaim(claim);
         logging::LOG_DEBUG(logger_) << "Import offset " << flowFile->getOffset() << " length " << flowFile->getSize() << " content " << flowFile->getResourceClaim()->getContentFullPath()
                                     << ", FlowFile UUID " << flowFile->getUUIDStr();
-        stream->closeStream();
+        stream->close();
         std::string details = process_context_->getProcessorNode()->getName() + " modify flow record content " + flowFile->getUUIDStr();
         uint64_t endTime = utils::timeutils::getTimeMillis();
         provenance_report_->modifyContent(flowFile, details, endTime - startTime);
@@ -894,7 +894,7 @@
     std::map<std::shared_ptr<Connectable>, std::vector<std::shared_ptr<core::FlowFile> > >& transactionMap,
     const std::map<std::string, std::shared_ptr<FlowFile>>& originalFlowFileSnapShots) {
 
-  std::vector<std::pair<std::string, std::unique_ptr<io::DataStream>>> flowData;
+  std::vector<std::pair<std::string, std::unique_ptr<io::BufferStream>>> flowData;
 
   auto flowFileRepo = process_context_->getFlowFileRepository();
   auto contentRepo = process_context_->getContentRepository();
@@ -911,7 +911,7 @@
       }
       FlowFileRecord event(flowFileRepo, contentRepo, ff, target->getUUIDStr());
 
-      std::unique_ptr<io::DataStream> stream(new io::DataStream());
+      std::unique_ptr<io::BufferStream> stream(new io::BufferStream());
       event.Serialize(*stream);
 
       flowData.emplace_back(event.getUUIDStr(), std::move(stream));
diff --git a/libminifi/src/core/ProcessSessionReadCallback.cpp b/libminifi/src/core/ProcessSessionReadCallback.cpp
index 254c1f5..d0009bd 100644
--- a/libminifi/src/core/ProcessSessionReadCallback.cpp
+++ b/libminifi/src/core/ProcessSessionReadCallback.cpp
@@ -58,7 +58,7 @@
       return -1;
     }
     size += read;
-  } while (size < stream->getSize());
+  } while (size < stream->size());
   _writeSucceeded = true;
   return size;
 }
diff --git a/libminifi/src/core/Repository.cpp b/libminifi/src/core/Repository.cpp
index 8c5fa43..bb0eee0 100644
--- a/libminifi/src/core/Repository.cpp
+++ b/libminifi/src/core/Repository.cpp
@@ -19,8 +19,7 @@
 #include <cstdint>
 #include <vector>
 
-#include "io/DataStream.h"
-#include "io/Serializable.h"
+#include "io/BufferStream.h"
 #include "core/Relationship.h"
 #include "core/logging/Logger.h"
 #include "FlowController.h"
diff --git a/libminifi/src/io/AtomicEntryStream.cpp b/libminifi/src/io/AtomicEntryStream.cpp
index aac9723..388fc8f 100644
--- a/libminifi/src/io/AtomicEntryStream.cpp
+++ b/libminifi/src/io/AtomicEntryStream.cpp
@@ -19,7 +19,6 @@
 #include <vector>
 #include <mutex>
 #include <string>
-#include "io/Serializable.h"
 
 namespace org {
 namespace apache {
diff --git a/libminifi/src/io/BaseStream.cpp b/libminifi/src/io/BaseStream.cpp
index bcd9111..0137473 100644
--- a/libminifi/src/io/BaseStream.cpp
+++ b/libminifi/src/io/BaseStream.cpp
@@ -18,7 +18,6 @@
 #include "io/BaseStream.h"
 #include <vector>
 #include <string>
-#include "io/Serializable.h"
 #include "core/expect.h"
 
 namespace org {
@@ -26,177 +25,7 @@
 namespace nifi {
 namespace minifi {
 namespace io {
-/**
- * write 4 bytes to stream
- * @param base_value non encoded value
- * @param stream output stream
- * @param is_little_endian endianness determination
- * @return resulting write size
- **/
-int BaseStream::write(uint32_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, composable_stream_, is_little_endian);
-}
 
-int BaseStream::writeData(uint8_t *value, int size) {
-  if (LIKELY(composable_stream_ == this)) {
-    return DataStream::writeData(value, size);
-  } else {
-    return composable_stream_->writeData(value, size);
-  }
-}
-
-/**
- * write 2 bytes to stream
- * @param base_value non encoded value
- * @param stream output stream
- * @param is_little_endian endianness determination
- * @return resulting write size
- **/
-int BaseStream::write(uint16_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, composable_stream_, is_little_endian);
-}
-
-/**
- * write valueto stream
- * @param value non encoded value
- * @param len length of value
- * @param strema output stream
- * @return resulting write size
- **/
-int BaseStream::write(uint8_t *value, int len) {
-  return Serializable::write(value, len, composable_stream_);
-}
-
-/**
- * write 8 bytes to stream
- * @param base_value non encoded value
- * @param stream output stream
- * @param is_little_endian endianness determination
- * @return resulting write size
- **/
-int BaseStream::write(uint64_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, composable_stream_, is_little_endian);
-}
-
-/**
- * write bool to stream
- * @param value non encoded value
- * @return resulting write size
- **/
-int BaseStream::write(bool value) {
-  uint8_t v = value;
-  return Serializable::write(v, composable_stream_);
-}
-
-/**
- * write UTF string to stream
- * @param str string to write
- * @return resulting write size
- **/
-int BaseStream::writeUTF(std::string str, bool widen) {
-  return Serializable::writeUTF(str, composable_stream_, widen);
-}
-
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::read(uint8_t &value) {
-  return Serializable::read(value, composable_stream_);
-}
-
-/**
- * reads two bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::read(uint16_t &base_value, bool is_little_endian) {
-  if (LIKELY(composable_stream_ == this))
-    return DataStream::read(base_value, is_little_endian);
-  else
-    return Serializable::read(base_value, composable_stream_);
-}
-
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::read(char &value) {
-  return Serializable::read(value, composable_stream_);
-}
-
-/**
- * reads a byte array from the stream
- * @param value reference in which will set the result
- * @param len length to read
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::read(uint8_t *value, int len) {
-  return Serializable::read(value, len, composable_stream_);
-}
-
-/**
- * Reads data and places it into buf
- * @param buf buffer in which we extract data
- * @param buflen
- */
-int BaseStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  return Serializable::read(&buf[0], buflen, composable_stream_);
-}
-/**
- * Reads data and places it into buf
- * @param buf buffer in which we extract data
- * @param buflen
- */
-int BaseStream::readData(uint8_t *buf, int buflen) {
-  if (LIKELY(composable_stream_ == this)) {
-    return DataStream::readData(buf, buflen);
-  } else {
-    return Serializable::read(buf, buflen, composable_stream_);
-  }
-}
-
-/**
- * reads four bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::read(uint32_t &value, bool is_little_endian) {
-  if (LIKELY(composable_stream_ == this))
-    return DataStream::read(value, is_little_endian);
-  else
-    return Serializable::read(value, composable_stream_, is_little_endian);
-}
-
-/**
- * reads eight byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::read(uint64_t &value, bool is_little_endian) {
-  if (LIKELY(composable_stream_ == this))
-    return DataStream::read(value, is_little_endian);
-  else
-    return Serializable::read(value, composable_stream_, is_little_endian);
-}
-
-/**
- * read UTF from stream
- * @param str reference string
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int BaseStream::readUTF(std::string &str, bool widen) {
-  return Serializable::readUTF(str, composable_stream_, widen);
-}
 } /* namespace io */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/libminifi/src/io/BufferStream.cpp b/libminifi/src/io/BufferStream.cpp
new file mode 100644
index 0000000..83860c5
--- /dev/null
+++ b/libminifi/src/io/BufferStream.cpp
@@ -0,0 +1,50 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdint>
+#include <algorithm>
+#include "io/BufferStream.h"
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+int BufferStream::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
+  buffer_.reserve(buffer_.size() + size);
+  std::copy(value, value + size, std::back_inserter(buffer_));
+  return size;
+}
+
+int BufferStream::read(uint8_t *buf, int len) {
+  gsl_Expects(len >= 0);
+  len = (std::min<uint64_t>)(len, buffer_.size() - readOffset_);
+  auto begin = buffer_.begin() + readOffset_;
+  std::copy(begin, begin + len, buf);
+
+  // increase offset for the next read
+  readOffset_ += len;
+
+  return len;
+}
+
+} /* namespace io */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
diff --git a/libminifi/src/io/ClientSocket.cpp b/libminifi/src/io/ClientSocket.cpp
index ffdae03..b1cda1a 100644
--- a/libminifi/src/io/ClientSocket.cpp
+++ b/libminifi/src/io/ClientSocket.cpp
@@ -27,6 +27,12 @@
 #pragma comment(lib, "Ws2_32.lib")
 #endif /* !WIN32 */
 
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
 #include <memory>
 #include <utility>
 #include <vector>
@@ -41,7 +47,6 @@
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/file/FileUtils.h"
 #include "utils/GeneralUtils.h"
-
 namespace util = org::apache::nifi::minifi::utils;
 namespace mio = org::apache::nifi::minifi::io;
 
@@ -213,16 +218,16 @@
 }
 
 Socket::~Socket() {
-  Socket::closeStream();
+  close();
 }
 
-void Socket::closeStream() {
+void Socket::close() {
   if (valid_socket(socket_file_descriptor_)) {
     logging::LOG_DEBUG(logger_) << "Closing " << socket_file_descriptor_;
 #ifdef WIN32
     closesocket(socket_file_descriptor_);
 #else
-    close(socket_file_descriptor_);
+    ::close(socket_file_descriptor_);
 #endif
     socket_file_descriptor_ = INVALID_SOCKET;
   }
@@ -255,14 +260,14 @@
       const auto bind_result = bind(socket_file_descriptor_, current_addr->ai_addr, current_addr->ai_addrlen);
       if (bind_result == SOCKET_ERROR) {
         logger_->log_warn("bind: %s", get_last_socket_error_message());
-        closeStream();
+        close();
         continue;
       }
 
       const auto listen_result = listen(socket_file_descriptor_, listeners_);
       if (listen_result == SOCKET_ERROR) {
         logger_->log_warn("listen: %s", get_last_socket_error_message());
-        closeStream();
+        close();
         continue;
       }
 
@@ -280,7 +285,7 @@
       const auto connect_result = connect(socket_file_descriptor_, current_addr->ai_addr, current_addr->ai_addrlen);
       if (connect_result == SOCKET_ERROR) {
         logger_->log_warn("Couldn't connect to %s:%" PRIu16 ": %s", sockaddr_ntop(current_addr->ai_addr), port_, get_last_socket_error_message());
-        closeStream();
+        close();
         continue;
       }
 
@@ -353,7 +358,7 @@
     }
     if (connect(socket_file_descriptor_, reinterpret_cast<const sockaddr *>(&sa_loc), sizeof(sockaddr_in)) < 0) {
 #endif /* WIN32 */
-      closeStream();
+      close();
       return -1;
     }
   }
@@ -365,7 +370,7 @@
   return 0;
 }
 
-int16_t Socket::initialize() {
+int Socket::initialize() {
   addrinfo hints{};
   memset(&hints, 0, sizeof hints);  // make sure the struct is empty
   hints.ai_family = AF_UNSPEC;
@@ -458,19 +463,19 @@
 #ifndef __MACH__
   if (setsockopt(sock, SOL_TCP, TCP_NODELAY, static_cast<void*>(&opt), sizeof(opt)) < 0) {
     logger_->log_error("setsockopt() TCP_NODELAY failed");
-    close(sock);
+    ::close(sock);
     return -1;
   }
   if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&opt), sizeof(opt)) < 0) {
     logger_->log_error("setsockopt() SO_REUSEADDR failed");
-    close(sock);
+    ::close(sock);
     return -1;
   }
 
   int sndsize = 256 * 1024;
   if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char *>(&sndsize), sizeof(sndsize)) < 0) {
     logger_->log_error("setsockopt() SO_SNDBUF failed");
-    close(sock);
+    ::close(sock);
     return -1;
   }
 
@@ -479,7 +484,7 @@
     // lose the pesky "address already in use" error message
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&opt), sizeof(opt)) < 0) {
       logger_->log_error("setsockopt() SO_REUSEADDR failed");
-      close(sock);
+      ::close(sock);
       return -1;
     }
   }
@@ -492,19 +497,11 @@
   return canonical_hostname_;
 }
 
-int Socket::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen))
-    return -1;
-  return writeData(buf.data(), buflen);
-}
-
 // data stream overrides
 
-int Socket::writeData(uint8_t *value, int size) {
+int Socket::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
+
   int ret = 0, bytes = 0;
 
   int fd = select_descriptor(1000);
@@ -526,84 +523,8 @@
   return bytes;
 }
 
-template<typename T>
-inline std::vector<uint8_t> Socket::readBuffer(const T& t) {
-  std::vector<uint8_t> buf;
-  readBuffer(buf, t);
-  return buf;
-}
-
-template<typename T>
-inline int Socket::readBuffer(std::vector<uint8_t>& buf, const T& t) {
-  buf.resize(sizeof t);
-  return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-}
-
-int Socket::write(uint64_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, this, is_little_endian);
-}
-
-int Socket::write(uint32_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, this, is_little_endian);
-}
-
-int Socket::write(uint16_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, this, is_little_endian);
-}
-
-int Socket::read(uint64_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if(ret <= 0)return ret;
-
-  if (is_little_endian) {
-    value = ((uint64_t) buf[0] << 56) | ((uint64_t) (buf[1] & 255) << 48) | ((uint64_t) (buf[2] & 255) << 40) | ((uint64_t) (buf[3] & 255) << 32) | ((uint64_t) (buf[4] & 255) << 24)
-        | ((uint64_t) (buf[5] & 255) << 16) | ((uint64_t) (buf[6] & 255) << 8) | ((uint64_t) (buf[7] & 255) << 0);
-  } else {
-    value = ((uint64_t) buf[0] << 0) | ((uint64_t) (buf[1] & 255) << 8) | ((uint64_t) (buf[2] & 255) << 16) | ((uint64_t) (buf[3] & 255) << 24) | ((uint64_t) (buf[4] & 255) << 32)
-        | ((uint64_t) (buf[5] & 255) << 40) | ((uint64_t) (buf[6] & 255) << 48) | ((uint64_t) (buf[7] & 255) << 56);
-  }
-  return sizeof(value);
-}
-
-int Socket::read(uint32_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if(ret <= 0)return ret;
-
-  if (is_little_endian) {
-    value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-  } else {
-    value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-  }
-  return sizeof(value);
-}
-
-int Socket::read(uint16_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if(ret <= 0)return ret;
-
-  if (is_little_endian) {
-    value = (buf[0] << 8) | buf[1];
-  } else {
-    value = buf[0] | buf[1] << 8;
-  }
-  return sizeof(value);
-}
-
-int Socket::readData(std::vector<uint8_t> &buf, int buflen, bool retrieve_all_bytes) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  return readData(buf.data(), buflen, retrieve_all_bytes);
-}
-
-int Socket::readData(uint8_t *buf, int buflen, bool retrieve_all_bytes) {
+int Socket::read(uint8_t *buf, int buflen, bool retrieve_all_bytes) {
+  gsl_Expects(buflen >= 0);
   int32_t total_read = 0;
   while (buflen) {
     int16_t fd = select_descriptor(1000);
diff --git a/libminifi/src/io/DataStream.cpp b/libminifi/src/io/DataStream.cpp
deleted file mode 100644
index 8912f7b..0000000
--- a/libminifi/src/io/DataStream.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "io/DataStream.h"
-#include <vector>
-#include <cstdint>
-#include <string>
-#include <algorithm>
-#include <iterator>
-#include <cassert>
-#include <Exception.h>
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace io {
-
-int DataStream::writeData(uint8_t *value, int size) {
-  if (value == nullptr)
-    return 0;
-  std::size_t previous_size = buffer.size();
-  buffer.resize(previous_size + size);
-  std::memcpy(buffer.data() + previous_size, value, size);
-  return size;
-}
-
-int DataStream::read(uint64_t &value, bool is_little_endian) {
-  if ((8 + readBuffer) > buffer.size()) {
-    // if read exceed
-    return -1;
-  }
-  uint8_t *buf = &buffer[readBuffer];
-
-  if (is_little_endian) {
-    value = ((uint64_t) buf[0] << 56) | ((uint64_t) (buf[1] & 255) << 48) | ((uint64_t) (buf[2] & 255) << 40) | ((uint64_t) (buf[3] & 255) << 32) | ((uint64_t) (buf[4] & 255) << 24)
-        | ((uint64_t) (buf[5] & 255) << 16) | ((uint64_t) (buf[6] & 255) << 8) | ((uint64_t) (buf[7] & 255) << 0);
-  } else {
-    value = ((uint64_t) buf[0] << 0) | ((uint64_t) (buf[1] & 255) << 8) | ((uint64_t) (buf[2] & 255) << 16) | ((uint64_t) (buf[3] & 255) << 24) | ((uint64_t) (buf[4] & 255) << 32)
-        | ((uint64_t) (buf[5] & 255) << 40) | ((uint64_t) (buf[6] & 255) << 48) | ((uint64_t) (buf[7] & 255) << 56);
-  }
-  readBuffer += 8;
-  return 8;
-}
-
-int DataStream::read(uint32_t &value, bool is_little_endian) {
-  if ((4 + readBuffer) > buffer.size()) {
-    // if read exceed
-    return -1;
-  }
-  uint8_t *buf = &buffer[readBuffer];
-
-  if (is_little_endian) {
-    value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-  } else {
-    value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-  }
-  readBuffer += 4;
-  return 4;
-}
-
-int DataStream::read(uint16_t &value, bool is_little_endian) {
-  if ((2 + readBuffer) > buffer.size()) {
-    // if read exceed
-    return -1;
-  }
-  uint8_t *buf = &buffer[readBuffer];
-
-  if (is_little_endian) {
-    value = (buf[0] << 8) | buf[1];
-  } else {
-    value = buf[0] | buf[1] << 8;
-  }
-  readBuffer += 2;
-  return 2;
-}
-
-int DataStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if ((buflen + readBuffer) > buffer.size()) {
-    // if read exceed
-    return -1;
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen))
-    buf.resize(buflen);
-
-  return this->doReadData(buf.data(), buflen);
-}
-
-int DataStream::readData(uint8_t *buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ ExceptionType::GENERAL_EXCEPTION, "negative buflen" };
-  }
-
-  if ((buflen + readBuffer) > buffer.size()) {
-    // if read exceed
-    return -1;
-  }
-
-  return this->doReadData(buf, buflen);
-}
-
-int DataStream::doReadData(uint8_t *buf, int buflen) noexcept {
-  const auto read_start = std::next(std::begin(buffer), readBuffer);
-  const auto read_end = std::next(read_start, buflen);
-  const auto write_end = std::copy(read_start, read_end, buf);
-
-  assert(std::distance(buf, write_end) == buflen && "read buflen bytes");
-  (void)write_end;
-
-  // increase offset for the next read
-  readBuffer += buflen;
-
-  return buflen;
-}
-
-} /* namespace io */
-} /* namespace minifi */
-} /* namespace nifi */
-} /* namespace apache */
-} /* namespace org */
diff --git a/libminifi/src/io/DescriptorStream.cpp b/libminifi/src/io/DescriptorStream.cpp
index 549c1b5..99bf97c 100644
--- a/libminifi/src/io/DescriptorStream.cpp
+++ b/libminifi/src/io/DescriptorStream.cpp
@@ -43,20 +43,8 @@
 #endif
 }
 
-int DescriptorStream::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    return -1;
-  }
-  return writeData(buf.data(), buflen);
-}
-
-// data stream overrides
-
-int DescriptorStream::writeData(uint8_t *value, int size) {
+int DescriptorStream::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
   if (!IsNullOrEmpty(value)) {
     std::lock_guard<std::recursive_mutex> lock(file_lock_);
 #ifdef WIN32
@@ -73,36 +61,8 @@
   }
 }
 
-template<typename T>
-inline std::vector<uint8_t> DescriptorStream::readBuffer(const T& t) {
-  std::vector<uint8_t> buf;
-  readBuffer(buf, t);
-  return buf;
-}
-
-template<typename T>
-inline int DescriptorStream::readBuffer(std::vector<uint8_t>& buf, const T& t) {
-  buf.resize(sizeof t);
-  return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-}
-
-int DescriptorStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int ret = readData(buf.data(), buflen);
-
-  if (ret < buflen) {
-    buf.resize((std::max)(ret, 0));
-  }
-  return ret;
-}
-
-int DescriptorStream::readData(uint8_t *buf, int buflen) {
+int DescriptorStream::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   if (!IsNullOrEmpty(buf)) {
 #ifdef WIN32
     auto size_read = _read(fd_, buf, buflen);
@@ -120,104 +80,6 @@
   }
 }
 
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::read(uint8_t &value) {
-  return Serializable::read(value, reinterpret_cast<DataStream*>(this));
-}
-
-/**
- * reads two bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::read(uint16_t &base_value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, base_value);
-  if (ret <= 0) return ret;
-  if (is_little_endian) {
-    base_value = (buf[0] << 8) | buf[1];
-  } else {
-    base_value = buf[0] | buf[1] << 8;
-  }
-  return 2;
-}
-
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::read(char &value) {
-  return readData(reinterpret_cast<uint8_t*>(&value), 1);
-}
-
-/**
- * reads a byte array from the stream
- * @param value reference in which will set the result
- * @param len length to read
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::read(uint8_t *value, int len) {
-  return readData(value, len);
-}
-
-/**
- * reads four bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::read(uint32_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-  if (is_little_endian) {
-    value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-  } else {
-    value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-  }
-  return 4;
-}
-
-/**
- * reads eight byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::read(uint64_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-
-  if (is_little_endian) {
-    value = ((uint64_t) buf[0] << 56) | ((uint64_t) (buf[1] & 255) << 48) | ((uint64_t) (buf[2] & 255) << 40) | ((uint64_t) (buf[3] & 255) << 32) | ((uint64_t) (buf[4] & 255) << 24)
-        | ((uint64_t) (buf[5] & 255) << 16) | ((uint64_t) (buf[6] & 255) << 8) | ((uint64_t) (buf[7] & 255) << 0);
-  } else {
-    value = ((uint64_t) buf[0] << 0) | ((uint64_t) (buf[1] & 255) << 8) | ((uint64_t) (buf[2] & 255) << 16) | ((uint64_t) (buf[3] & 255) << 24) | ((uint64_t) (buf[4] & 255) << 32)
-        | ((uint64_t) (buf[5] & 255) << 40) | ((uint64_t) (buf[6] & 255) << 48) | ((uint64_t) (buf[7] & 255) << 56);
-  }
-  return 8;
-}
-
-/**
- * read UTF from stream
- * @param str reference string
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int DescriptorStream::readUTF(std::string &str, bool widen) {
-  return Serializable::readUTF(str, reinterpret_cast<DataStream*>(this), widen);
-}
-
 } /* namespace io */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/libminifi/src/io/FileStream.cpp b/libminifi/src/io/FileStream.cpp
index 15cc112..b64ca98 100644
--- a/libminifi/src/io/FileStream.cpp
+++ b/libminifi/src/io/FileStream.cpp
@@ -16,13 +16,15 @@
  * limitations under the License.
  */
 
-#include "io/FileStream.h"
 #include <fstream>
 #include <vector>
 #include <memory>
 #include <string>
 #include <Exception.h>
 #include "io/validation.h"
+#include "io/FileStream.h"
+#include "io/InputStream.h"
+#include "io/OutputStream.h"
 namespace org {
 namespace apache {
 namespace nifi {
@@ -68,7 +70,7 @@
   seek(offset);
 }
 
-void FileStream::closeStream() {
+void FileStream::close() {
   std::lock_guard<std::mutex> lock(file_lock_);
   file_stream_.reset();
 }
@@ -81,20 +83,8 @@
   file_stream_->seekp(offset_);
 }
 
-int FileStream::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    return -1;
-  }
-  return writeData(buf.data(), buflen);
-}
-
-// data stream overrides
-
-int FileStream::writeData(uint8_t *value, int size) {
+int FileStream::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
   if (!IsNullOrEmpty(value)) {
     std::lock_guard<std::mutex> lock(file_lock_);
     if (file_stream_->write(reinterpret_cast<const char*>(value), size)) {
@@ -114,36 +104,8 @@
   }
 }
 
-template<typename T>
-inline std::vector<uint8_t> FileStream::readBuffer(const T& t) {
-  std::vector<uint8_t> buf;
-  readBuffer(buf, t);
-  return buf;
-}
-
-template<typename T>
-inline int FileStream::readBuffer(std::vector<uint8_t>& buf, const T& t) {
-  buf.resize(sizeof t);
-  return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-}
-
-int FileStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int ret = readData(buf.data(), buflen);
-
-  if (ret < buflen) {
-    buf.resize(ret);
-  }
-  return ret;
-}
-
-int FileStream::readData(uint8_t *buf, int buflen) {
+int FileStream::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   if (!IsNullOrEmpty(buf)) {
     std::lock_guard<std::mutex> lock(file_lock_);
     if (!file_stream_) {
diff --git a/libminifi/src/io/InputStream.cpp b/libminifi/src/io/InputStream.cpp
new file mode 100644
index 0000000..e395e83
--- /dev/null
+++ b/libminifi/src/io/InputStream.cpp
@@ -0,0 +1,83 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdio>
+#include <iostream>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include "io/InputStream.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+int InputStream::read(std::vector<uint8_t>& buffer, int len) {
+  if (buffer.size() < len) {
+    buffer.resize(len);
+  }
+  int ret = read(buffer.data(), len);
+  buffer.resize((std::max)(ret, 0));
+  return ret;
+}
+
+int InputStream::read(bool &value) {
+  uint8_t buf = 0;
+
+  if (read(&buf, 1) != 1) {
+    return -1;
+  }
+  value = buf;
+  return 1;
+}
+
+int InputStream::read(std::string &str, bool widen) {
+  uint32_t len = 0;
+  int ret = 0;
+  if (!widen) {
+    uint16_t shortLength = 0;
+    ret = read(shortLength);
+    len = shortLength;
+  } else {
+    ret = read(len);
+  }
+
+  if (ret <= 0) {
+    return ret;
+  }
+
+  if (len == 0) {
+    str = "";
+    return ret;
+  }
+
+  std::vector<uint8_t> buffer(len);
+  if (read(buffer.data(), len) != len) {
+    return -1;
+  }
+
+  str = std::string(reinterpret_cast<const char*>(buffer.data()), len);
+  return ret + len;
+}
+
+} /* namespace io */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
diff --git a/libminifi/src/io/NonConvertingStream.cpp b/libminifi/src/io/NonConvertingStream.cpp
deleted file mode 100644
index 07bb130..0000000
--- a/libminifi/src/io/NonConvertingStream.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "io/NonConvertingStream.h"
-#include <vector>
-#include <string>
-#include "io/Serializable.h"
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace io {
-/**
- * write 4 bytes to stream
- * @param base_value non encoded value
- * @param stream output stream
- * @param is_little_endian endianness determination
- * @return resulting write size
- **/
-int NonConvertingStream::write(uint32_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, reinterpret_cast<DataStream*>(composable_stream_), is_little_endian);
-}
-
-int NonConvertingStream::writeData(uint8_t *value, int size) {
-  if (composable_stream_ == this) {
-    return DataStream::writeData(value, size);
-  } else {
-    return composable_stream_->writeData(value, size);
-  }
-}
-
-/**
- * write 2 bytes to stream
- * @param base_value non encoded value
- * @param stream output stream
- * @param is_little_endian endianness determination
- * @return resulting write size
- **/
-int NonConvertingStream::write(uint16_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, reinterpret_cast<DataStream*>(composable_stream_), is_little_endian);
-}
-
-/**
- * write valueto stream
- * @param value non encoded value
- * @param len length of value
- * @param strema output stream
- * @return resulting write size
- **/
-int NonConvertingStream::write(uint8_t *value, int len) {
-  return Serializable::write(value, len, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * write 8 bytes to stream
- * @param base_value non encoded value
- * @param stream output stream
- * @param is_little_endian endianness determination
- * @return resulting write size
- **/
-int NonConvertingStream::write(uint64_t base_value, bool is_little_endian) {
-  return Serializable::write(base_value, reinterpret_cast<DataStream*>(composable_stream_), is_little_endian);
-}
-
-/**
- * write bool to stream
- * @param value non encoded value
- * @return resulting write size
- **/
-int NonConvertingStream::write(bool value) {
-  uint8_t v = value;
-  return Serializable::write(v, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * write UTF string to stream
- * @param str string to write
- * @return resulting write size
- **/
-int NonConvertingStream::writeUTF(std::string str, bool widen) {
-  return Serializable::writeUTF(str, reinterpret_cast<DataStream*>(composable_stream_), widen);
-}
-
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::read(uint8_t &value) {
-  return Serializable::read(value, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * reads two bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::read(uint16_t &base_value, bool is_little_endian) {
-  return Serializable::read(base_value, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::read(char &value) {
-  return Serializable::read(value, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * reads a byte array from the stream
- * @param value reference in which will set the result
- * @param len length to read
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::read(uint8_t *value, int len) {
-  return Serializable::read(value, len, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * Reads data and places it into buf
- * @param buf buffer in which we extract data
- * @param buflen
- */
-int NonConvertingStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  return Serializable::read(&buf[0], buflen, reinterpret_cast<DataStream*>(composable_stream_));
-}
-/**
- * Reads data and places it into buf
- * @param buf buffer in which we extract data
- * @param buflen
- */
-int NonConvertingStream::readData(uint8_t *buf, int buflen) {
-  return Serializable::read(buf, buflen, reinterpret_cast<DataStream*>(composable_stream_));
-}
-
-/**
- * reads four bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::read(uint32_t &value, bool is_little_endian) {
-  return Serializable::read(value, reinterpret_cast<DataStream*>(composable_stream_), is_little_endian);
-}
-
-/**
- * reads eight byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::read(uint64_t &value, bool is_little_endian) {
-  return Serializable::read(value, reinterpret_cast<DataStream*>(composable_stream_), is_little_endian);
-}
-
-/**
- * read UTF from stream
- * @param str reference string
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int NonConvertingStream::readUTF(std::string &str, bool widen) {
-  return Serializable::readUTF(str, reinterpret_cast<DataStream*>(composable_stream_), widen);
-}
-} /* namespace io */
-} /* namespace minifi */
-} /* namespace nifi */
-} /* namespace apache */
-} /* namespace org */
diff --git a/libminifi/src/io/OutputStream.cpp b/libminifi/src/io/OutputStream.cpp
new file mode 100644
index 0000000..efbc02f
--- /dev/null
+++ b/libminifi/src/io/OutputStream.cpp
@@ -0,0 +1,79 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include "io/OutputStream.h"
+
+namespace org {
+namespace apache {
+namespace nifi {
+namespace minifi {
+namespace io {
+
+int OutputStream::write(const std::vector<uint8_t>& buffer, int len) {
+  if (buffer.size() < len) {
+    return -1;
+  }
+  return write(buffer.data(), len);
+}
+
+int OutputStream::write(bool value) {
+  uint8_t temp = value;
+  return write(&temp, 1);
+}
+
+int OutputStream::write(const std::string& str, bool widen) {
+  return write_str(str.c_str(), str.length(), widen);
+}
+
+int OutputStream::write(const char* str, bool widen) {
+  return write_str(str, std::strlen(str), widen);
+}
+
+int OutputStream::write_str(const char* str, uint32_t len, bool widen) {
+  int ret = 0;
+  if (!widen) {
+    uint16_t shortLen = len;
+    if (len != shortLen) {
+      return -1;
+    }
+    ret = write(shortLen);
+  } else {
+    ret = write(len);
+  }
+
+  if (ret <= 0) {
+    return ret;
+  }
+
+  if (len == 0) {
+    return ret;
+  }
+
+  return ret + write(reinterpret_cast<const uint8_t *>(str), len);
+}
+
+} /* namespace io */
+} /* namespace minifi */
+} /* namespace nifi */
+} /* namespace apache */
+} /* namespace org */
diff --git a/libminifi/src/io/Serializable.cpp b/libminifi/src/io/Serializable.cpp
deleted file mode 100644
index a9e8e78..0000000
--- a/libminifi/src/io/Serializable.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "io/Serializable.h"
-#include <cstdio>
-#include <iostream>
-#include <vector>
-#include <string>
-#include <algorithm>
-#include "io/DataStream.h"
-
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace io {
-
-#define IS_ASCII(c) __builtin_expect(!!((c >= 1) && (c <= 127)), 1)
-
-int Serializable::write(uint8_t value, DataStream *stream) {
-  return stream->writeData(&value, 1);
-}
-int Serializable::write(char value, DataStream *stream) {
-  return stream->writeData(reinterpret_cast<uint8_t *>(&value), 1);
-}
-
-int Serializable::write(const uint8_t * const value, int len, DataStream *stream) {
-  return stream->writeData(const_cast<uint8_t *>(value), len);
-}
-
-int Serializable::write(bool value, DataStream *stream) {
-  uint8_t temp = value;
-  return stream->writeData(&temp, 1);
-}
-
-int Serializable::read(uint8_t &value, DataStream *stream) {
-  uint8_t buf;
-
-  int ret = stream->readData(&buf, 1);
-  if (ret == 1)
-    value = buf;
-  return ret;
-}
-
-int Serializable::read(char &value, DataStream *stream) {
-  uint8_t buf;
-
-  int ret = stream->readData(&buf, 1);
-  if (ret == 1)
-    value = buf;
-  return ret;
-}
-
-int Serializable::read(uint8_t *value, int len, DataStream *stream) {
-  return stream->readData(value, len);
-}
-
-int Serializable::readUTF(std::string &str, DataStream *stream, bool widen) {
-  uint32_t utflen = 0;
-  int ret = 1;
-  if (!widen) {
-    uint16_t shortLength = 0;
-    ret = read(shortLength, stream);
-    utflen = shortLength;
-  } else {
-    ret = read(utflen, stream);
-  }
-
-  if (ret <= 0)
-    return ret;
-
-  if (utflen == 0) {
-    str = "";
-    return 1;
-  }
-
-  std::vector<uint8_t> buf;
-  stream->readData(buf, utflen);
-
-  // The number of chars produced may be less than utflen
-  str = std::string((const char*) &buf[0], utflen);
-  return utflen;
-}
-
-int Serializable::writeUTF(std::string str, DataStream *stream, bool widen) {
-  uint32_t utflen = 0;
-
-  utflen = str.length();
-
-  if (utflen > 65535)
-    return -1;
-
-  if (!widen) {
-    uint16_t shortLen = utflen;
-    write(shortLen, stream);
-  } else {
-    write(utflen, stream);
-  }
-
-  if (utflen == 0) {
-    return 1;
-  }
-
-  return stream->writeData(reinterpret_cast<uint8_t *>(const_cast<char*>(str.c_str())), utflen);
-}
-
-} /* namespace io */
-} /* namespace minifi */
-} /* namespace nifi */
-} /* namespace apache */
-} /* namespace org */
diff --git a/libminifi/src/io/ZlibStream.cpp b/libminifi/src/io/ZlibStream.cpp
index 353ca84..8e58dc5 100644
--- a/libminifi/src/io/ZlibStream.cpp
+++ b/libminifi/src/io/ZlibStream.cpp
@@ -18,22 +18,15 @@
 
 #include "io/ZlibStream.h"
 #include "Exception.h"
-
 namespace org {
 namespace apache {
 namespace nifi {
 namespace minifi {
 namespace io {
 
-/* ZlibBaseStream */
-
-ZlibBaseStream::ZlibBaseStream()
-    : ZlibBaseStream(this) {
-}
-
-ZlibBaseStream::ZlibBaseStream(DataStream* other)
-    : BaseStream(other)
-    , outputBuffer_(16384U) {
+ZlibBaseStream::ZlibBaseStream(gsl::not_null<OutputStream*> output)
+    : output_{output},
+      outputBuffer_(16384U) {
   strm_.zalloc = Z_NULL;
   strm_.zfree = Z_NULL;
   strm_.opaque = Z_NULL;
@@ -43,14 +36,8 @@
   return state_ == ZlibStreamState::FINISHED;
 }
 
-/* ZlibCompressStream */
-
-ZlibCompressStream::ZlibCompressStream(ZlibCompressionFormat format, int level)
-  : ZlibCompressStream(this, format, level) {
-}
-
-ZlibCompressStream::ZlibCompressStream(DataStream* other, ZlibCompressionFormat format, int level)
-  : ZlibBaseStream(other) {
+ZlibCompressStream::ZlibCompressStream(gsl::not_null<OutputStream*> output, ZlibCompressionFormat format, int level)
+  : ZlibBaseStream(output) {
   int ret = deflateInit2(
       &strm_,
       level,
@@ -72,13 +59,14 @@
   }
 }
 
-int ZlibCompressStream::writeData(uint8_t* value, int size) {
+int ZlibCompressStream::write(const uint8_t* value, int size) {
+  gsl_Expects(size >= 0);
   if (state_ != ZlibStreamState::INITIALIZED) {
     logger_->log_error("writeData called in invalid ZlibCompressStream state, state is %hhu", state_);
     return -1;
   }
 
-  strm_.next_in = value;
+  strm_.next_in = const_cast<uint8_t*>(value);
   strm_.avail_in = size;
 
   /*
@@ -106,7 +94,7 @@
     }
     int output_size = outputBuffer_.size() - strm_.avail_out;
     logger_->log_trace("deflate produced %d B of output data", output_size);
-    if (BaseStream::writeData(outputBuffer_.data(), output_size) != output_size) {
+    if (output_->write(outputBuffer_.data(), output_size) != output_size) {
       logger_->log_error("Failed to write to underlying stream");
       state_ = ZlibStreamState::ERRORED;
       return -1;
@@ -116,22 +104,16 @@
   return size;
 }
 
-void ZlibCompressStream::closeStream() {
+void ZlibCompressStream::close() {
   if (state_ == ZlibStreamState::INITIALIZED) {
-    if (writeData(nullptr, 0U) == 0) {
+    if (write(nullptr, 0U) == 0) {
       state_ = ZlibStreamState::FINISHED;
     }
   }
 }
 
-/* ZlibDecompressStream */
-
-ZlibDecompressStream::ZlibDecompressStream(ZlibCompressionFormat format)
-  : ZlibDecompressStream(this, format) {
-}
-
-ZlibDecompressStream::ZlibDecompressStream(DataStream* other, ZlibCompressionFormat format)
-    : ZlibBaseStream(other) {
+ZlibDecompressStream::ZlibDecompressStream(gsl::not_null<OutputStream*> output, ZlibCompressionFormat format)
+    : ZlibBaseStream(output) {
   int ret = inflateInit2(&strm_, 15 + (format == ZlibCompressionFormat::GZIP ? 16 : 0) /* windowBits */);
   if (ret != Z_OK) {
     logger_->log_error("Failed to initialize z_stream with inflateInit2, error code: %d", ret);
@@ -147,13 +129,14 @@
   }
 }
 
-int ZlibDecompressStream::writeData(uint8_t* value, int size) {
+int ZlibDecompressStream::write(const uint8_t* value, int size) {
+  gsl_Expects(size >= 0);
   if (state_ != ZlibStreamState::INITIALIZED) {
     logger_->log_error("writeData called in invalid ZlibDecompressStream state, state is %hhu", state_);
     return -1;
   }
 
-  strm_.next_in = value;
+  strm_.next_in = const_cast<uint8_t*>(value);
   strm_.avail_in = size;
 
   /*
@@ -179,7 +162,7 @@
     }
     int output_size = outputBuffer_.size() - strm_.avail_out;
     logger_->log_trace("deflate produced %d B of output data", output_size);
-    if (BaseStream::writeData(outputBuffer_.data(), output_size) != output_size) {
+    if (output_->write(outputBuffer_.data(), output_size) != output_size) {
       logger_->log_error("Failed to write to underlying stream");
       state_ = ZlibStreamState::ERRORED;
       return -1;
diff --git a/libminifi/src/io/tls/SecureDescriptorStream.cpp b/libminifi/src/io/tls/SecureDescriptorStream.cpp
index 8b1edac..694959e 100644
--- a/libminifi/src/io/tls/SecureDescriptorStream.cpp
+++ b/libminifi/src/io/tls/SecureDescriptorStream.cpp
@@ -43,20 +43,10 @@
 #endif
 }
 
-int SecureDescriptorStream::writeData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    return -1;
-  }
-  return writeData(buf.data(), buflen);
-}
-
 // data stream overrides
 
-int SecureDescriptorStream::writeData(uint8_t *value, int size) {
+int SecureDescriptorStream::write(const uint8_t *value, int size) {
+  gsl_Expects(size >= 0);
   if (!IsNullOrEmpty(value)) {
     std::lock_guard<std::recursive_mutex> lock(file_lock_);
     int bytes = 0;
@@ -78,36 +68,8 @@
   }
 }
 
-template<typename T>
-inline std::vector<uint8_t> SecureDescriptorStream::readBuffer(const T& t) {
-  std::vector<uint8_t> buf;
-  readBuffer(buf, t);
-  return buf;
-}
-
-template<typename T>
-inline int SecureDescriptorStream::readBuffer(std::vector<uint8_t>& buf, const T& t) {
-  buf.resize(sizeof t);
-  return readData(reinterpret_cast<uint8_t *>(&buf[0]), sizeof(t));
-}
-
-int SecureDescriptorStream::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int ret = readData(buf.data(), buflen);
-
-  if (ret < buflen) {
-    buf.resize((std::max)(ret, 0));
-  }
-  return ret;
-}
-
-int SecureDescriptorStream::readData(uint8_t *buf, int buflen) {
+int SecureDescriptorStream::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   if (!IsNullOrEmpty(buf)) {
     int total_read = 0;
       int status = 0;
@@ -133,104 +95,6 @@
   }
 }
 
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::read(uint8_t &value) {
-  return Serializable::read(value, reinterpret_cast<DataStream*>(this));
-}
-
-/**
- * reads two bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::read(uint16_t &base_value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, base_value);
-  if (ret <= 0) return ret;
-  if (is_little_endian) {
-    base_value = (buf[0] << 8) | buf[1];
-  } else {
-    base_value = buf[0] | buf[1] << 8;
-  }
-  return 2;
-}
-
-/**
- * reads a byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::read(char &value) {
-  return readData(reinterpret_cast<uint8_t*>(&value), 1);
-}
-
-/**
- * reads a byte array from the stream
- * @param value reference in which will set the result
- * @param len length to read
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::read(uint8_t *value, int len) {
-  return readData(value, len);
-}
-
-/**
- * reads four bytes from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::read(uint32_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-  if (is_little_endian) {
-    value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-  } else {
-    value = buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
-  }
-  return 4;
-}
-
-/**
- * reads eight byte from the stream
- * @param value reference in which will set the result
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::read(uint64_t &value, bool is_little_endian) {
-  std::vector<uint8_t> buf;
-  auto ret = readBuffer(buf, value);
-  if (ret <= 0) return ret;
-
-  if (is_little_endian) {
-    value = ((uint64_t) buf[0] << 56) | ((uint64_t) (buf[1] & 255) << 48) | ((uint64_t) (buf[2] & 255) << 40) | ((uint64_t) (buf[3] & 255) << 32) | ((uint64_t) (buf[4] & 255) << 24)
-        | ((uint64_t) (buf[5] & 255) << 16) | ((uint64_t) (buf[6] & 255) << 8) | ((uint64_t) (buf[7] & 255) << 0);
-  } else {
-    value = ((uint64_t) buf[0] << 0) | ((uint64_t) (buf[1] & 255) << 8) | ((uint64_t) (buf[2] & 255) << 16) | ((uint64_t) (buf[3] & 255) << 24) | ((uint64_t) (buf[4] & 255) << 32)
-        | ((uint64_t) (buf[5] & 255) << 40) | ((uint64_t) (buf[6] & 255) << 48) | ((uint64_t) (buf[7] & 255) << 56);
-  }
-  return 8;
-}
-
-/**
- * read UTF from stream
- * @param str reference string
- * @param stream stream from which we will read
- * @return resulting read size
- **/
-int SecureDescriptorStream::readUTF(std::string &str, bool widen) {
-  return Serializable::readUTF(str, reinterpret_cast<DataStream*>(this), widen);
-}
-
 } /* namespace io */
 } /* namespace minifi */
 } /* namespace nifi */
diff --git a/libminifi/src/io/tls/TLSSocket.cpp b/libminifi/src/io/tls/TLSSocket.cpp
index eb85185..6e5e0ee 100644
--- a/libminifi/src/io/tls/TLSSocket.cpp
+++ b/libminifi/src/io/tls/TLSSocket.cpp
@@ -34,7 +34,6 @@
 #include "core/Property.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/GeneralUtils.h"
-
 namespace org {
 namespace apache {
 namespace nifi {
@@ -148,15 +147,15 @@
 }
 
 TLSSocket::~TLSSocket() {
-  TLSSocket::closeStream();
+  TLSSocket::close();
 }
 
-void TLSSocket::closeStream() {
+void TLSSocket::close() {
   if (ssl_ != 0) {
     SSL_free(ssl_);
     ssl_ = nullptr;
   }
-  Socket::closeStream();
+  Socket::close();
 }
 
 /**
@@ -239,7 +238,7 @@
         return 0;
       } else {
         logger_->log_error("SSL socket connect failed to %s %d", requested_hostname_, port_);
-        closeStream();
+        close();
         return -1;
       }
     } else {
@@ -260,7 +259,7 @@
     if (nullptr != fd_ssl) {
       SSL_free(fd_ssl);
       ssl_map_[fd] = nullptr;
-      closeStream();
+      close();
     }
   }
 }
@@ -329,7 +328,7 @@
           return socket_file_descriptor_;
         } else {
           logger_->log_error("SSL socket connect failed (%d) to %s %d", ssl_error, requested_hostname_, port_);
-          closeStream();
+          close();
           return -1;
         }
       }
@@ -352,33 +351,14 @@
   return -1;
 }
 
-int TLSSocket::writeData(std::vector<uint8_t>& buf, int buflen) {
-  int16_t fd = select_descriptor(1000);
-  if (fd < 0) {
-    closeStream();
-    return -1;
-  }
-  return writeData(buf.data(), buflen, fd);
-}
-
-int TLSSocket::readData(std::vector<uint8_t> &buf, int buflen, bool retrieve_all_bytes) {
-  if (buflen < 0) {
-    throw minifi::Exception{ExceptionType::GENERAL_EXCEPTION, "negative buflen"};
-  }
-
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  return readData(buf.data(), buflen, retrieve_all_bytes);
-}
-
-int TLSSocket::readData(uint8_t *buf, int buflen, bool retrieve_all_bytes) {
+int TLSSocket::read(uint8_t *buf, int buflen, bool retrieve_all_bytes) {
+  gsl_Expects(buflen >= 0);
   int total_read = 0;
   int status = 0;
   int loc = 0;
   int16_t fd = select_descriptor(1000);
   if (fd < 0) {
-    closeStream();
+    close();
     return -1;
   }
   auto fd_ssl = get_ssl(fd);
@@ -406,41 +386,8 @@
   return total_read;
 }
 
-int TLSSocket::readData(std::vector<uint8_t> &buf, int buflen) {
-  if (buflen < 0)
-    return -1;
-  if (buf.size() < static_cast<size_t>(buflen)) {
-    buf.resize(buflen);
-  }
-  int total_read = 0;
-  int status = 0;
-  int loc = 0;
-  while (buflen) {
-    int16_t fd = select_descriptor(1000);
-    if (fd < 0) {
-      closeStream();
-      return -1;
-    }
-
-    auto fd_ssl = get_ssl(fd);
-    if (IsNullOrEmpty(fd_ssl)) {
-      return -1;
-    }
-    int sslStatus;
-    do {
-      status = SSL_read(fd_ssl, buf.data() + loc, buflen);
-      sslStatus = SSL_get_error(fd_ssl, status);
-    } while (status < 0 && sslStatus == SSL_ERROR_WANT_READ);
-
-    buflen -= status;
-    loc += status;
-    total_read += status;
-  }
-
-  return total_read;
-}
-
-int TLSSocket::writeData(uint8_t *value, int size, int fd) {
+int TLSSocket::writeData(const uint8_t *value, unsigned int size, int fd) {
+  gsl_Expects(size >= 0);
   int bytes = 0;
   int sent = 0;
   auto fd_ssl = get_ssl(fd);
@@ -463,39 +410,23 @@
   return size;
 }
 
-int TLSSocket::writeData(uint8_t *value, int size) {
-  int bytes = 0;
-  int sent = 0;
+int TLSSocket::write(const uint8_t *value, int size) {
   int fd = select_descriptor(1000);
   if (fd < 0) {
-    closeStream();
+    close();
     return -1;
   }
-  auto fd_ssl = get_ssl(fd);
-  if (IsNullOrEmpty(fd_ssl)) {
-    return -1;
-  }
-  while (bytes < size) {
-    sent = SSL_write(fd_ssl, value + bytes, size - bytes);
-    // check for errors
-    if (sent < 0) {
-      int ret = 0;
-      ret = SSL_get_error(fd_ssl, sent);
-      logger_->log_error("WriteData socket %d send failed %s %d", fd, strerror(errno), ret);
-      return sent;
-    }
-    bytes += sent;
-  }
-  return size;
+  return writeData(value, size, fd);
 }
 
-int TLSSocket::readData(uint8_t *buf, int buflen) {
+int TLSSocket::read(uint8_t *buf, int buflen) {
+  gsl_Expects(buflen >= 0);
   int total_read = 0;
   int status = 0;
   while (buflen) {
     int16_t fd = select_descriptor(1000);
     if (fd < 0) {
-      closeStream();
+      close();
       return -1;
     }
 
diff --git a/libminifi/src/provenance/Provenance.cpp b/libminifi/src/provenance/Provenance.cpp
index 2578a4b..cbbc59d 100644
--- a/libminifi/src/provenance/Provenance.cpp
+++ b/libminifi/src/provenance/Provenance.cpp
@@ -23,8 +23,7 @@
 #include <vector>
 #include <list>
 #include "core/Repository.h"
-#include "io/DataStream.h"
-#include "io/Serializable.h"
+#include "io/BufferStream.h"
 #include "core/logging/Logger.h"
 #include "core/Relationship.h"
 #include "FlowController.h"
@@ -72,107 +71,107 @@
     logger_->log_debug("NiFi Provenance Read event %s", uuidStr_);
   }
 
-  org::apache::nifi::minifi::io::DataStream stream((const uint8_t*) value.data(), value.length());
+  org::apache::nifi::minifi::io::BufferStream stream((const uint8_t*) value.data(), value.length());
 
   ret = DeSerialize(stream);
 
   if (ret) {
-    logger_->log_debug("NiFi Provenance retrieve event %s size %llu eventType %d success", uuidStr_, stream.getSize(), _eventType);
+    logger_->log_debug("NiFi Provenance retrieve event %s size %llu eventType %d success", uuidStr_, stream.size(), _eventType);
   } else {
-    logger_->log_debug("NiFi Provenance retrieve event %s size %llu eventType %d fail", uuidStr_, stream.getSize(), _eventType);
+    logger_->log_debug("NiFi Provenance retrieve event %s size %llu eventType %d fail", uuidStr_, stream.size(), _eventType);
   }
 
   return ret;
 }
 
-bool ProvenanceEventRecord::Serialize(org::apache::nifi::minifi::io::DataStream& outStream) {
+bool ProvenanceEventRecord::Serialize(org::apache::nifi::minifi::io::BufferStream& outStream) {
   int ret;
 
-  ret = writeUTF(this->uuidStr_, &outStream);
+  ret = outStream.write(this->uuidStr_);
   if (ret <= 0) {
     return false;
   }
 
   uint32_t eventType = this->_eventType;
-  ret = write(eventType, &outStream);
+  ret = outStream.write(eventType);
   if (ret != 4) {
     return false;
   }
 
-  ret = write(this->_eventTime, &outStream);
+  ret = outStream.write(this->_eventTime);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->_entryDate, &outStream);
+  ret = outStream.write(this->_entryDate);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->_eventDuration, &outStream);
+  ret = outStream.write(this->_eventDuration);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->_lineageStartDate, &outStream);
+  ret = outStream.write(this->_lineageStartDate);
   if (ret != 8) {
     return false;
   }
 
-  ret = writeUTF(this->_componentId, &outStream);
+  ret = outStream.write(this->_componentId);
   if (ret <= 0) {
     return false;
   }
 
-  ret = writeUTF(this->_componentType, &outStream);
+  ret = outStream.write(this->_componentType);
   if (ret <= 0) {
     return false;
   }
 
-  ret = writeUTF(this->flow_uuid_, &outStream);
+  ret = outStream.write(this->flow_uuid_);
   if (ret <= 0) {
     return false;
   }
 
-  ret = writeUTF(this->_details, &outStream);
+  ret = outStream.write(this->_details);
   if (ret <= 0) {
     return false;
   }
 
   // write flow attributes
   uint32_t numAttributes = this->_attributes.size();
-  ret = write(numAttributes, &outStream);
+  ret = outStream.write(numAttributes);
   if (ret != 4) {
     return false;
   }
 
   for (const auto& itAttribute : _attributes) {
-    ret = writeUTF(itAttribute.first, &outStream, true);
+    ret = outStream.write(itAttribute.first);
     if (ret <= 0) {
       return false;
     }
-    ret = writeUTF(itAttribute.second, &outStream, true);
+    ret = outStream.write(itAttribute.second);
     if (ret <= 0) {
       return false;
     }
   }
 
-  ret = writeUTF(this->_contentFullPath, &outStream);
+  ret = outStream.write(this->_contentFullPath);
   if (ret <= 0) {
     return false;
   }
 
-  ret = write(this->_size, &outStream);
+  ret = outStream.write(this->_size);
   if (ret != 8) {
     return false;
   }
 
-  ret = write(this->_offset, &outStream);
+  ret = outStream.write(this->_offset);
   if (ret != 8) {
     return false;
   }
 
-  ret = writeUTF(this->_sourceQueueIdentifier, &outStream);
+  ret = outStream.write(this->_sourceQueueIdentifier);
   if (ret <= 0) {
     return false;
   }
@@ -180,38 +179,38 @@
   if (this->_eventType == ProvenanceEventRecord::FORK || this->_eventType == ProvenanceEventRecord::CLONE || this->_eventType == ProvenanceEventRecord::JOIN) {
     // write UUIDs
     uint32_t number = this->_parentUuids.size();
-    ret = write(number, &outStream);
+    ret = outStream.write(number);
     if (ret != 4) {
       return false;
     }
     for (const auto& parentUUID : _parentUuids) {
-      ret = writeUTF(parentUUID, &outStream);
+      ret = outStream.write(parentUUID);
       if (ret <= 0) {
         return false;
       }
     }
     number = this->_childrenUuids.size();
-    ret = write(number, &outStream);
+    ret = outStream.write(number);
     if (ret != 4) {
       return false;
     }
     for (const auto& childUUID : _childrenUuids) {
-      ret = writeUTF(childUUID, &outStream);
+      ret = outStream.write(childUUID);
       if (ret <= 0) {
         return false;
       }
     }
   } else if (this->_eventType == ProvenanceEventRecord::SEND || this->_eventType == ProvenanceEventRecord::FETCH) {
-    ret = writeUTF(this->_transitUri, &outStream);
+    ret = outStream.write(this->_transitUri);
     if (ret <= 0) {
       return false;
     }
   } else if (this->_eventType == ProvenanceEventRecord::RECEIVE) {
-    ret = writeUTF(this->_transitUri, &outStream);
+    ret = outStream.write(this->_transitUri);
     if (ret <= 0) {
       return false;
     }
-    ret = writeUTF(this->_sourceSystemFlowFileIdentifier, &outStream);
+    ret = outStream.write(this->_sourceSystemFlowFileIdentifier);
     if (ret <= 0) {
       return false;
     }
@@ -221,13 +220,13 @@
 }
 
 bool ProvenanceEventRecord::Serialize(const std::shared_ptr<core::SerializableComponent> &repo) {
-  org::apache::nifi::minifi::io::DataStream outStream;
+  org::apache::nifi::minifi::io::BufferStream outStream;
 
   Serialize(outStream);
 
   // Persist to the DB
-  if (!repo->Serialize(uuidStr_, const_cast<uint8_t*>(outStream.getBuffer()), outStream.getSize())) {
-    logger_->log_error("NiFi Provenance Store event %s size %llu fail", uuidStr_, outStream.getSize());
+  if (!repo->Serialize(uuidStr_, const_cast<uint8_t*>(outStream.getBuffer()), outStream.size())) {
+    logger_->log_error("NiFi Provenance Store event %s size %llu fail", uuidStr_, outStream.size());
   }
   return true;
 }
@@ -235,57 +234,57 @@
 bool ProvenanceEventRecord::DeSerialize(const uint8_t *buffer, const size_t bufferSize) {
   int ret;
 
-  org::apache::nifi::minifi::io::DataStream outStream(buffer, bufferSize);
+  org::apache::nifi::minifi::io::BufferStream outStream(buffer, bufferSize);
 
-  ret = readUTF(this->uuidStr_, &outStream);
+  ret = outStream.read(this->uuidStr_);
 
   if (ret <= 0) {
     return false;
   }
 
   uint32_t eventType;
-  ret = read(eventType, &outStream);
+  ret = outStream.read(eventType);
   if (ret != 4) {
     return false;
   }
   this->_eventType = (ProvenanceEventRecord::ProvenanceEventType) eventType;
 
-  ret = read(this->_eventTime, &outStream);
+  ret = outStream.read(this->_eventTime);
   if (ret != 8) {
     return false;
   }
 
-  ret = read(this->_entryDate, &outStream);
+  ret = outStream.read(this->_entryDate);
   if (ret != 8) {
     return false;
   }
 
-  ret = read(this->_eventDuration, &outStream);
+  ret = outStream.read(this->_eventDuration);
   if (ret != 8) {
     return false;
   }
 
-  ret = read(this->_lineageStartDate, &outStream);
+  ret = outStream.read(this->_lineageStartDate);
   if (ret != 8) {
     return false;
   }
 
-  ret = readUTF(this->_componentId, &outStream);
+  ret = outStream.read(this->_componentId);
   if (ret <= 0) {
     return false;
   }
 
-  ret = readUTF(this->_componentType, &outStream);
+  ret = outStream.read(this->_componentType);
   if (ret <= 0) {
     return false;
   }
 
-  ret = readUTF(this->flow_uuid_, &outStream);
+  ret = outStream.read(this->flow_uuid_);
   if (ret <= 0) {
     return false;
   }
 
-  ret = readUTF(this->_details, &outStream);
+  ret = outStream.read(this->_details);
 
   if (ret <= 0) {
     return false;
@@ -293,41 +292,41 @@
 
   // read flow attributes
   uint32_t numAttributes = 0;
-  ret = read(numAttributes, &outStream);
+  ret = outStream.read(numAttributes);
   if (ret != 4) {
     return false;
   }
 
   for (uint32_t i = 0; i < numAttributes; i++) {
     std::string key;
-    ret = readUTF(key, &outStream, true);
+    ret = outStream.read(key);
     if (ret <= 0) {
       return false;
     }
     std::string value;
-    ret = readUTF(value, &outStream, true);
+    ret = outStream.read(value);
     if (ret <= 0) {
       return false;
     }
     this->_attributes[key] = value;
   }
 
-  ret = readUTF(this->_contentFullPath, &outStream);
+  ret = outStream.read(this->_contentFullPath);
   if (ret <= 0) {
     return false;
   }
 
-  ret = read(this->_size, &outStream);
+  ret = outStream.read(this->_size);
   if (ret != 8) {
     return false;
   }
 
-  ret = read(this->_offset, &outStream);
+  ret = outStream.read(this->_offset);
   if (ret != 8) {
     return false;
   }
 
-  ret = readUTF(this->_sourceQueueIdentifier, &outStream);
+  ret = outStream.read(this->_sourceQueueIdentifier);
   if (ret <= 0) {
     return false;
   }
@@ -335,43 +334,43 @@
   if (this->_eventType == ProvenanceEventRecord::FORK || this->_eventType == ProvenanceEventRecord::CLONE || this->_eventType == ProvenanceEventRecord::JOIN) {
     // read UUIDs
     uint32_t number = 0;
-    ret = read(number, &outStream);
+    ret = outStream.read(number);
     if (ret != 4) {
       return false;
     }
 
     for (uint32_t i = 0; i < number; i++) {
       std::string parentUUID;
-      ret = readUTF(parentUUID, &outStream);
+      ret = outStream.read(parentUUID);
       if (ret <= 0) {
         return false;
       }
       this->addParentUuid(parentUUID);
     }
     number = 0;
-    ret = read(number, &outStream);
+    ret = outStream.read(number);
     if (ret != 4) {
       return false;
     }
     for (uint32_t i = 0; i < number; i++) {
       std::string childUUID;
-      ret = readUTF(childUUID, &outStream);
+      ret = outStream.read(childUUID);
       if (ret <= 0) {
         return false;
       }
       this->addChildUuid(childUUID);
     }
   } else if (this->_eventType == ProvenanceEventRecord::SEND || this->_eventType == ProvenanceEventRecord::FETCH) {
-    ret = readUTF(this->_transitUri, &outStream);
+    ret = outStream.read(this->_transitUri);
     if (ret <= 0) {
       return false;
     }
   } else if (this->_eventType == ProvenanceEventRecord::RECEIVE) {
-    ret = readUTF(this->_transitUri, &outStream);
+    ret = outStream.read(this->_transitUri);
     if (ret <= 0) {
       return false;
     }
-    ret = readUTF(this->_sourceSystemFlowFileIdentifier, &outStream);
+    ret = outStream.read(this->_sourceSystemFlowFileIdentifier);
     if (ret <= 0) {
       return false;
     }
@@ -390,10 +389,10 @@
     return;
   }
 
-  std::vector<std::pair<std::string, std::unique_ptr<io::DataStream>>> flowData;
+  std::vector<std::pair<std::string, std::unique_ptr<io::BufferStream>>> flowData;
 
   for (auto& event : _events) {
-    std::unique_ptr<io::DataStream> stramptr(new io::DataStream());
+    std::unique_ptr<io::BufferStream> stramptr(new io::BufferStream());
     event->Serialize(*stramptr.get());
 
     flowData.emplace_back(event->getUUIDStr(), std::move(stramptr));
diff --git a/libminifi/src/sitetosite/Peer.cpp b/libminifi/src/sitetosite/Peer.cpp
index 9859659..3ed6b70 100644
--- a/libminifi/src/sitetosite/Peer.cpp
+++ b/libminifi/src/sitetosite/Peer.cpp
@@ -56,7 +56,7 @@
 
   int data_size = gsl::narrow<int>(sizeof MAGIC_BYTES);
 
-  if (stream_->writeData(reinterpret_cast<uint8_t *>(const_cast<char*>(MAGIC_BYTES)), data_size) != data_size) {
+  if (stream_->write(reinterpret_cast<uint8_t *>(const_cast<char*>(MAGIC_BYTES)), data_size) != data_size) {
     return false;
   }
 
@@ -65,7 +65,7 @@
 
 void SiteToSitePeer::Close() {
   if (stream_ != nullptr)
-    stream_->closeStream();
+    stream_->close();
 }
 
 } /* namespace sitetosite */
diff --git a/libminifi/src/sitetosite/RawSocketProtocol.cpp b/libminifi/src/sitetosite/RawSocketProtocol.cpp
index f17241e..6575391 100644
--- a/libminifi/src/sitetosite/RawSocketProtocol.cpp
+++ b/libminifi/src/sitetosite/RawSocketProtocol.cpp
@@ -113,7 +113,7 @@
 
   logger_->log_debug("Negotiate protocol version with destination port %s current version %d", port_id_str_, _currentVersion);
 
-  int ret = peer_->writeUTF(getResourceName());
+  int ret = peer_->write(getResourceName());
 
   logger_->log_trace("result of writing resource name is %i", ret);
   if (ret <= 0) {
@@ -177,7 +177,7 @@
 
   logger_->log_trace("Negotiate Codec version with destination port %s current version %d", port_id_str_, _currentCodecVersion);
 
-  int ret = peer_->writeUTF(getCodecResourceName());
+  int ret = peer_->write(getCodecResourceName());
 
   if (ret <= 0) {
     logger_->log_debug("result of getCodecResourceName is %i", ret);
@@ -239,7 +239,7 @@
   id_generator_->generate(uuid);
   _commsIdentifier = uuid.to_string();
 
-  int ret = peer_->writeUTF(_commsIdentifier);
+  int ret = peer_->write(_commsIdentifier);
 
   if (ret <= 0) {
     return false;
@@ -259,7 +259,7 @@
   }
 
   if (_currentVersion >= 3) {
-    ret = peer_->writeUTF(peer_->getURL());
+    ret = peer_->write(peer_->getURL());
     if (ret <= 0) {
       return false;
     }
@@ -273,11 +273,11 @@
 
   std::map<std::string, std::string>::iterator it;
   for (it = properties.begin(); it != properties.end(); it++) {
-    ret = peer_->writeUTF(it->first);
+    ret = peer_->write(it->first);
     if (ret <= 0) {
       return false;
     }
-    ret = peer_->writeUTF(it->second);
+    ret = peer_->write(it->second);
     if (ret <= 0) {
       return false;
     }
@@ -353,7 +353,7 @@
 
     for (uint32_t i = 0; i < number; i++) {
       std::string host;
-      status = peer_->readUTF(host);
+      status = peer_->read(host);
       if (status <= 0) {
         tearDown();
         return false;
@@ -393,13 +393,13 @@
     if (type >= MAX_REQUEST_TYPE)
       return -1;
 
-    return peer_->writeUTF(SiteToSiteRequest::RequestTypeStr[type]);
+    return peer_->write(SiteToSiteRequest::RequestTypeStr[type]);
   }
 
   int RawSiteToSiteClient::readRequestType(RequestType &type) {
     std::string requestTypeStr;
 
-    int ret = peer_->readUTF(requestTypeStr);
+    int ret = peer_->read(requestTypeStr);
 
     if (ret <= 0)
       return ret;
@@ -495,12 +495,12 @@
       return transaction;
     }
 
-    org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> crcstream(peer_.get());
+    org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> crcstream(gsl::make_not_null(peer_.get()));
     switch (code) {
       case MORE_DATA:
         dataAvailable = true;
         logger_->log_trace("Site2Site peer indicates that data is available");
-        transaction = std::make_shared<Transaction>(direction, crcstream);
+        transaction = std::make_shared<Transaction>(direction, std::move(crcstream));
         known_transactions_[transaction->getUUIDStr()] = transaction;
         transactionID = transaction->getUUIDStr();
         transaction->setDataAvailable(dataAvailable);
@@ -509,7 +509,7 @@
       case NO_MORE_DATA:
         dataAvailable = false;
         logger_->log_trace("Site2Site peer indicates that no data is available");
-        transaction = std::make_shared<Transaction>(direction, crcstream);
+        transaction = std::make_shared<Transaction>(direction, std::move(crcstream));
         known_transactions_[transaction->getUUIDStr()] = transaction;
         transactionID = transaction->getUUIDStr();
         transaction->setDataAvailable(dataAvailable);
@@ -525,8 +525,8 @@
     if (ret <= 0) {
       return NULL;
     } else {
-      org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> crcstream(peer_.get());
-      transaction = std::make_shared<Transaction>(direction, crcstream);
+      org::apache::nifi::minifi::io::CRCStream<SiteToSitePeer> crcstream(gsl::make_not_null(peer_.get()));
+      transaction = std::make_shared<Transaction>(direction, std::move(crcstream));
       known_transactions_[transaction->getUUIDStr()] = transaction;
       transactionID = transaction->getUUIDStr();
       logger_->log_trace("Site2Site create transaction %s", transaction->getUUIDStr());
diff --git a/libminifi/src/sitetosite/SiteToSiteClient.cpp b/libminifi/src/sitetosite/SiteToSiteClient.cpp
index 0099c31..2ba142b 100644
--- a/libminifi/src/sitetosite/SiteToSiteClient.cpp
+++ b/libminifi/src/sitetosite/SiteToSiteClient.cpp
@@ -56,7 +56,7 @@
     return -1;
   }
   if (resCode->hasDescription) {
-    ret = peer_->readUTF(message);
+    ret = peer_->read(message);
     if (ret <= 0)
       return -1;
   }
@@ -97,7 +97,7 @@
     return -1;
 
   if (resCode->hasDescription) {
-    ret = peer_->writeUTF(message);
+    ret = peer_->write(message);
     if (ret > 0) {
       return (3 + ret);
     } else {
@@ -449,12 +449,12 @@
 
   std::map<std::string, std::string>::iterator itAttribute;
   for (itAttribute = packet->_attributes.begin(); itAttribute != packet->_attributes.end(); itAttribute++) {
-    ret = transaction->getStream().writeUTF(itAttribute->first, true);
+    ret = transaction->getStream().write(itAttribute->first, true);
 
     if (ret <= 0) {
       return -1;
     }
-    ret = transaction->getStream().writeUTF(itAttribute->second, true);
+    ret = transaction->getStream().write(itAttribute->second, true);
     if (ret <= 0) {
       return -1;
     }
@@ -499,8 +499,7 @@
       return -1;
     }
 
-    ret = transaction->getStream().writeData(reinterpret_cast<uint8_t *>(const_cast<char*>(packet->payload_.c_str())),
-                                             gsl::narrow<int>(len));
+    ret = transaction->getStream().write(reinterpret_cast<uint8_t *>(const_cast<char*>(packet->payload_.c_str())), gsl::narrow<int>(len));
     if (ret != gsl::narrow<int64_t>(len)) {
       logger_->log_debug("Failed to write payload size!");
       return -1;
@@ -602,11 +601,11 @@
   for (unsigned int i = 0; i < numAttributes; i++) {
     std::string key;
     std::string value;
-    ret = transaction->getStream().readUTF(key, true);
+    ret = transaction->getStream().read(key, true);
     if (ret <= 0) {
       return false;
     }
-    ret = transaction->getStream().readUTF(value, true);
+    ret = transaction->getStream().read(value, true);
     if (ret <= 0) {
       return false;
     }
diff --git a/libminifi/src/utils/ByteArrayCallback.cpp b/libminifi/src/utils/ByteArrayCallback.cpp
index fe8397f..a2abe0f 100644
--- a/libminifi/src/utils/ByteArrayCallback.cpp
+++ b/libminifi/src/utils/ByteArrayCallback.cpp
@@ -28,11 +28,11 @@
 
 int64_t ByteOutputCallback::process(std::shared_ptr<io::BaseStream> stream) {
   stream->seek(0);
-  if (stream->getSize() > 0) {
-    std::unique_ptr<char> buffer = std::unique_ptr<char>(new char[stream->getSize()]);
-    readFully(buffer.get(), stream->getSize());
-    stream->readData(reinterpret_cast<uint8_t*>(buffer.get()), stream->getSize());
-    return stream->getSize();
+  if (stream->size() > 0) {
+    std::unique_ptr<char> buffer = std::unique_ptr<char>(new char[stream->size()]);
+    readFully(buffer.get(), stream->size());
+    stream->read(reinterpret_cast<uint8_t*>(buffer.get()), stream->size());
+    return stream->size();
   }
   return size_.load();
 }
@@ -41,8 +41,8 @@
   stream->seek(0);
   std::unique_ptr<char> buffer = std::unique_ptr<char>(new char[size_.load()]);
   auto written = readFully(buffer.get(), size_);
-  stream->writeData(reinterpret_cast<uint8_t*>(buffer.get()), written);
-  return stream->getSize();
+  stream->write(reinterpret_cast<uint8_t*>(buffer.get()), written);
+  return stream->size();
 }
 
 void StreamOutputCallback::write(char *data, size_t size) {
diff --git a/libminifi/src/utils/FileOutputCallback.cpp b/libminifi/src/utils/FileOutputCallback.cpp
index 8951291..182cf09 100644
--- a/libminifi/src/utils/FileOutputCallback.cpp
+++ b/libminifi/src/utils/FileOutputCallback.cpp
@@ -27,9 +27,9 @@
 namespace utils {
 
 int64_t FileOutputCallback::process(std::shared_ptr<io::BaseStream> stream) {
-  if (stream->getSize() > 0) {
-    file_stream_.write(reinterpret_cast<char*>(const_cast<uint8_t*>(stream->getBuffer())), stream->getSize());
-    size_ += stream->getSize();
+  if (stream->size() > 0) {
+    file_stream_.write(reinterpret_cast<char*>(const_cast<uint8_t*>(stream->getBuffer())), stream->size());
+    size_ += stream->size();
   }
   return size_.load();
 }
diff --git a/libminifi/test/BufferReader.h b/libminifi/test/BufferReader.h
index 3336279..caa0aa8 100644
--- a/libminifi/test/BufferReader.h
+++ b/libminifi/test/BufferReader.h
@@ -43,7 +43,7 @@
   }
 
   int64_t process(std::shared_ptr<org::apache::nifi::minifi::io::BaseStream> stream) {
-    return write(*stream.get(), stream->getSize());
+    return write(*stream.get(), stream->size());
   }
 
  private:
diff --git a/libminifi/test/archive-tests/MergeFileTests.cpp b/libminifi/test/archive-tests/MergeFileTests.cpp
index 24572cd..3b1f68a 100644
--- a/libminifi/test/archive-tests/MergeFileTests.cpp
+++ b/libminifi/test/archive-tests/MergeFileTests.cpp
@@ -80,7 +80,7 @@
   }
 
   template<class Input>
-  int write(Input input, std::size_t len) {
+  int write(Input& input, std::size_t len) {
     REQUIRE(size_ + len <= capacity_);
     int total_read = 0;
     do {
diff --git a/libminifi/test/persistence-tests/PersistenceTests.cpp b/libminifi/test/persistence-tests/PersistenceTests.cpp
index 6d376af..e81cde2 100644
--- a/libminifi/test/persistence-tests/PersistenceTests.cpp
+++ b/libminifi/test/persistence-tests/PersistenceTests.cpp
@@ -87,7 +87,7 @@
     processor->onSchedule(processorContext.get(), new core::ProcessSessionFactory(processorContext));
   }
   std::shared_ptr<core::FlowFile> write(const std::string& data) {
-    minifi::io::DataStream stream(reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
+    minifi::io::BufferStream stream(reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
     core::ProcessSession sessionGenFlowFile(inputContext);
     std::shared_ptr<core::FlowFile> flow = std::static_pointer_cast<core::FlowFile>(sessionGenFlowFile.create());
     sessionGenFlowFile.importFrom(stream, flow);
@@ -232,7 +232,7 @@
   void onTrigger(core::ProcessContext *context, core::ProcessSession *session) override {
     auto ff = session->get();
     std::string data = "<override>";
-    minifi::io::DataStream stream(reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
+    minifi::io::BufferStream stream(reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
     session->importFrom(stream, ff);
     session->transfer(ff, {"success", "d"});
   }
diff --git a/libminifi/test/rocksdb-tests/DBContentRepositoryTests.cpp b/libminifi/test/rocksdb-tests/DBContentRepositoryTests.cpp
index a6717f7..6409f3e 100644
--- a/libminifi/test/rocksdb-tests/DBContentRepositoryTests.cpp
+++ b/libminifi/test/rocksdb-tests/DBContentRepositoryTests.cpp
@@ -41,9 +41,9 @@
   auto claim = std::make_shared<minifi::ResourceClaim>(content_repo);
   auto stream = content_repo->write(*claim);
 
-  stream->writeUTF("well hello there");
+  stream->write("well hello there");
 
-  stream->closeStream();
+  stream->close();
 
   content_repo->stop();
   // reclaim the memory
@@ -58,14 +58,14 @@
   auto read_stream = content_repo->read(*claim);
 
   std::string readstr;
-  read_stream->readUTF(readstr);
+  read_stream->read(readstr);
 
   REQUIRE(readstr == "well hello there");
 
   // should not be able to write to the read stream
   // -1 will indicate that we were not able to write any data
 
-  REQUIRE(read_stream->writeUTF("other value") == -1);
+  REQUIRE(read_stream->write("other value") == -1);
 }
 
 TEST_CASE("Delete Claim", "[TestDBCR2]") {
@@ -82,9 +82,9 @@
   auto claim = std::make_shared<minifi::ResourceClaim>(content_repo);
   auto stream = content_repo->write(*claim);
 
-  stream->writeUTF("well hello there");
+  stream->write("well hello there");
 
-  stream->closeStream();
+  stream->close();
 
   content_repo->stop();
 
@@ -104,7 +104,7 @@
   std::string readstr;
 
   // -1 tell us we have an invalid stream
-  REQUIRE(read_stream->readUTF(readstr) == -1);
+  REQUIRE(read_stream->read(readstr) == -1);
 }
 
 TEST_CASE("Test Empty Claim", "[TestDBCR3]") {
@@ -122,7 +122,7 @@
 
   // we're writing nothing to the stream.
 
-  stream->closeStream();
+  stream->close();
 
   content_repo->stop();
 
@@ -140,7 +140,7 @@
   std::string readstr;
 
   // -1 tell us we have an invalid stream
-  REQUIRE(read_stream->readUTF(readstr) == -1);
+  REQUIRE(read_stream->read(readstr) == -1);
 }
 
 TEST_CASE("Delete NonExistent Claim", "[TestDBCR4]") {
@@ -157,9 +157,9 @@
   auto claim2 = std::make_shared<minifi::ResourceClaim>(content_repo);
   auto stream = content_repo->write(*claim);
 
-  stream->writeUTF("well hello there");
+  stream->write("well hello there");
 
-  stream->closeStream();
+  stream->close();
 
   content_repo->stop();
 
@@ -180,7 +180,7 @@
   std::string readstr;
 
   // -1 tell us we have an invalid stream
-  read_stream->readUTF(readstr);
+  read_stream->read(readstr);
 
   REQUIRE(readstr == "well hello there");
 }
@@ -199,9 +199,9 @@
   auto claim2 = std::make_shared<minifi::ResourceClaim>(content_repo);
   auto stream = content_repo->write(*claim);
 
-  stream->writeUTF("well hello there");
+  stream->write("well hello there");
 
-  stream->closeStream();
+  stream->close();
 
   content_repo->stop();
 
@@ -228,7 +228,7 @@
   std::string readstr;
 
   // -1 tell us we have an invalid stream
-  read_stream->readUTF(readstr);
+  read_stream->read(readstr);
 
   REQUIRE(readstr == "well hello there");
 }
diff --git a/libminifi/test/rocksdb-tests/RepoTests.cpp b/libminifi/test/rocksdb-tests/RepoTests.cpp
index 44dc8de..069433e 100644
--- a/libminifi/test/rocksdb-tests/RepoTests.cpp
+++ b/libminifi/test/rocksdb-tests/RepoTests.cpp
@@ -285,7 +285,7 @@
   auto flowController = std::make_shared<minifi::FlowController>(prov_repo, ff_repository, config, std::move(flowConfig), content_repo, "", true);
 
   std::string data = "banana";
-  minifi::io::DataStream content(reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
+  minifi::io::BufferStream content(reinterpret_cast<const uint8_t*>(data.c_str()), data.length());
 
   /**
    * Currently it is the Connection's responsibility to persist the incoming
diff --git a/libminifi/test/unit/CRCTests.cpp b/libminifi/test/unit/CRCTests.cpp
index 5ace8e1..6880eee 100644
--- a/libminifi/test/unit/CRCTests.cpp
+++ b/libminifi/test/unit/CRCTests.cpp
@@ -19,82 +19,82 @@
 #include <string>
 #include <vector>
 #include "io/CRCStream.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "../TestBase.h"
 
 TEST_CASE("Test CRC1", "[testcrc1]") {
-  org::apache::nifi::minifi::io::BaseStream base;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(&base);
-  test.writeData(reinterpret_cast<uint8_t*>(const_cast<char*>("cow")), 3);
+  org::apache::nifi::minifi::io::BufferStream base;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(gsl::make_not_null(&base));
+  test.write(reinterpret_cast<uint8_t*>(const_cast<char*>("cow")), 3);
   REQUIRE(2580823964 == test.getCRC());
 }
 
 TEST_CASE("Test CRC2", "[testcrc2]") {
-  org::apache::nifi::minifi::io::BaseStream base;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(&base);
+  org::apache::nifi::minifi::io::BufferStream base;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(gsl::make_not_null(&base));
   std::string fox = "the quick brown fox jumped over the brown fox";
   std::vector<uint8_t> charvect(fox.begin(), fox.end());
-  test.writeData(charvect, charvect.size());
+  test.write(charvect, charvect.size());
   REQUIRE(1922388889 == test.getCRC());
 }
 
 TEST_CASE("Test CRC3", "[testcrc3]") {
-  org::apache::nifi::minifi::io::BaseStream base;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(&base);
+  org::apache::nifi::minifi::io::BufferStream base;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(gsl::make_not_null(&base));
   uint64_t number = 7;
   test.write(number);
   REQUIRE(4215687882 == test.getCRC());
 }
 
 TEST_CASE("Test CRC4", "[testcrc4]") {
-  org::apache::nifi::minifi::io::BaseStream base;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(&base);
+  org::apache::nifi::minifi::io::BufferStream base;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(gsl::make_not_null(&base));
   uint32_t number = 7;
   test.write(number);
   REQUIRE(3206564543 == test.getCRC());
 }
 
 TEST_CASE("Test CRC5", "[testcrc5]") {
-  org::apache::nifi::minifi::io::BaseStream base;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(&base);
+  org::apache::nifi::minifi::io::BufferStream base;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test(gsl::make_not_null(&base));
   uint16_t number = 7;
   test.write(number);
   REQUIRE(3753740124 == test.getCRC());
 }
 
 TEST_CASE("CRCStream with initial crc = 0 is the same as without initial crc", "[initial_crc_arg]") {
-  org::apache::nifi::minifi::io::BaseStream base1;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_noinit(&base1);
+  org::apache::nifi::minifi::io::BufferStream base1;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_noinit(gsl::make_not_null(&base1));
 
-  org::apache::nifi::minifi::io::BaseStream base2;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_initzero(&base2, 0);
+  org::apache::nifi::minifi::io::BufferStream base2;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_initzero(gsl::make_not_null(&base2), 0);
 
   const std::string textString = "The quick brown fox jumps over the lazy dog";
   std::vector<uint8_t> textVector1(textString.begin(), textString.end());
   std::vector<uint8_t> textVector2(textString.begin(), textString.end());
 
-  test_noinit.writeData(textVector1, textVector1.size());
-  test_initzero.writeData(textVector2, textVector2.size());
+  test_noinit.write(textVector1, textVector1.size());
+  test_initzero.write(textVector2, textVector2.size());
   REQUIRE(test_noinit.getCRC() == test_initzero.getCRC());
 }
 
 TEST_CASE("CRCStream: one long write is the same as writing in two pieces", "[initial_crc_arg]") {
   const std::string textString = "The quick brown fox jumps over the lazy dog";
 
-  org::apache::nifi::minifi::io::BaseStream base_full;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_full(&base_full, 0);
+  org::apache::nifi::minifi::io::BufferStream base_full;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_full(gsl::make_not_null(&base_full), 0);
   std::vector<uint8_t> textVector_full(textString.begin(), textString.end());
-  test_full.writeData(textVector_full, textVector_full.size());
+  test_full.write(textVector_full, textVector_full.size());
 
-  org::apache::nifi::minifi::io::BaseStream base_piece1;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_piece1(&base_piece1, 0);
+  org::apache::nifi::minifi::io::BufferStream base_piece1;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_piece1(gsl::make_not_null(&base_piece1), 0);
   std::vector<uint8_t> textVector_piece1(textString.begin(), textString.begin() + 15);
-  test_piece1.writeData(textVector_piece1, textVector_piece1.size());
+  test_piece1.write(textVector_piece1, textVector_piece1.size());
 
-  org::apache::nifi::minifi::io::BaseStream base_piece2;
-  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_piece2(&base_piece2, test_piece1.getCRC());
+  org::apache::nifi::minifi::io::BufferStream base_piece2;
+  org::apache::nifi::minifi::io::CRCStream<org::apache::nifi::minifi::io::BaseStream> test_piece2(gsl::make_not_null(&base_piece2), test_piece1.getCRC());
   std::vector<uint8_t> textVector_piece2(textString.begin() + 15, textString.end());
-  test_piece2.writeData(textVector_piece2, textVector_piece2.size());
+  test_piece2.write(textVector_piece2, textVector_piece2.size());
 
   REQUIRE(test_full.getCRC() == test_piece2.getCRC());
 }
diff --git a/libminifi/test/unit/FileStreamTests.cpp b/libminifi/test/unit/FileStreamTests.cpp
index f7c9b2b..37a7955 100644
--- a/libminifi/test/unit/FileStreamTests.cpp
+++ b/libminifi/test/unit/FileStreamTests.cpp
@@ -39,7 +39,7 @@
 
   minifi::io::FileStream stream(path, 0, true);
   std::vector<uint8_t> readBuffer;
-  REQUIRE(stream.readData(readBuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(readBuffer, stream.size()) == stream.size());
 
   uint8_t* data = readBuffer.data();
 
@@ -53,7 +53,7 @@
 
   std::vector<uint8_t> verifybuffer;
 
-  REQUIRE(stream.readData(verifybuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(verifybuffer, stream.size()) == stream.size());
 
   data = verifybuffer.data();
 
@@ -77,7 +77,7 @@
 
   minifi::io::FileStream stream(path, 0, true);
   std::vector<uint8_t> readBuffer;
-  REQUIRE(stream.readData(readBuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(readBuffer, stream.size()) == stream.size());
 
   uint8_t* data = readBuffer.data();
 
@@ -91,7 +91,7 @@
 
   std::vector<uint8_t> verifybuffer;
 
-  REQUIRE(stream.readData(verifybuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(verifybuffer, stream.size()) == stream.size());
 
   data = verifybuffer.data();
 
@@ -115,7 +115,7 @@
 
   minifi::io::FileStream stream(path, 0, true);
   std::vector<uint8_t> readBuffer;
-  REQUIRE(stream.readData(readBuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(readBuffer, stream.size()) == stream.size());
 
   uint8_t* data = readBuffer.data();
 
@@ -129,7 +129,7 @@
 
   std::vector<uint8_t> verifybuffer;
 
-  REQUIRE(stream.readData(verifybuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(verifybuffer, stream.size()) == stream.size());
 
   data = verifybuffer.data();
 
@@ -153,7 +153,7 @@
 
   minifi::io::FileStream stream(path, 0, true);
   std::vector<uint8_t> readBuffer;
-  REQUIRE(stream.readData(readBuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(readBuffer, stream.size()) == stream.size());
 
   uint8_t* data = readBuffer.data();
 
@@ -167,7 +167,7 @@
 
   std::vector<uint8_t> verifybuffer;
 
-  REQUIRE(stream.readData(nullptr, stream.getSize()) == -1);
+  REQUIRE(stream.read(nullptr, stream.size()) == -1);
 
   data = verifybuffer.data();
 
@@ -191,7 +191,7 @@
 
   minifi::io::FileStream stream(path, 0, true);
   std::vector<uint8_t> readBuffer;
-  REQUIRE(stream.readData(readBuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(readBuffer, stream.size()) == stream.size());
 
   uint8_t* data = readBuffer.data();
 
@@ -201,7 +201,7 @@
 
   std::vector<uint8_t> verifybuffer;
 
-  REQUIRE(stream.readData(verifybuffer, 8192) == 8);
+  REQUIRE(stream.read(verifybuffer, 8192) == 8);
 
   data = verifybuffer.data();
 
@@ -226,7 +226,7 @@
 
   minifi::io::FileStream stream(path, 0, true);
   std::vector<uint8_t> readBuffer;
-  REQUIRE(stream.readData(readBuffer, stream.getSize()) == stream.getSize());
+  REQUIRE(stream.read(readBuffer, stream.size()) == stream.size());
 
   uint8_t* data = readBuffer.data();
 
@@ -234,13 +234,15 @@
 
   std::vector<uint8_t> verifybuffer;
 
-  for (int i = 0; i < 10; i++)
-    REQUIRE(stream.readData(verifybuffer, 8192) == 8192);
-  REQUIRE(stream.readData(verifybuffer, 8192) == 0);
+  for (int i = 0; i < 10; i++) {
+    REQUIRE(stream.read(verifybuffer, 8192) == 8192);
+  }
+  REQUIRE(stream.read(verifybuffer, 8192) == 0);
   stream.seek(0);
-  for (int i = 0; i < 10; i++)
-    REQUIRE(stream.readData(verifybuffer, 8192) == 8192);
-  REQUIRE(stream.readData(verifybuffer, 8192) == 0);
+  for (int i = 0; i < 10; i++) {
+    REQUIRE(stream.read(verifybuffer, 8192) == 8192);
+  }
+  REQUIRE(stream.read(verifybuffer, 8192) == 0);
 
   std::remove(ss.str().c_str());
 }
diff --git a/libminifi/test/unit/ProvenanceTestHelper.h b/libminifi/test/unit/ProvenanceTestHelper.h
index 96283d9..9acfa35 100644
--- a/libminifi/test/unit/ProvenanceTestHelper.h
+++ b/libminifi/test/unit/ProvenanceTestHelper.h
@@ -80,9 +80,9 @@
     return true;
   }
 
-  bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<minifi::io::DataStream>>>& data) override {
+  bool MultiPut(const std::vector<std::pair<std::string, std::unique_ptr<minifi::io::BufferStream>>>& data) override {
     for (const auto& item: data) {
-      if (!Put(item.first, item.second->getBuffer(), item.second->getSize())) {
+      if (!Put(item.first, item.second->getBuffer(), item.second->size())) {
         return false;
       }
     }
diff --git a/libminifi/test/unit/SerializationTests.cpp b/libminifi/test/unit/SerializationTests.cpp
index 029cde4..ac778a1 100644
--- a/libminifi/test/unit/SerializationTests.cpp
+++ b/libminifi/test/unit/SerializationTests.cpp
@@ -27,62 +27,39 @@
 #define FMT_DEFAULT fmt_lower
 
 TEST_CASE("TestWriteUTF", "[MINIFI193]") {
-  org::apache::nifi::minifi::io::DataStream baseStream;
-
-  org::apache::nifi::minifi::io::Serializable ser;
+  org::apache::nifi::minifi::io::BufferStream baseStream;
 
   std::string stringOne = "helo world";  // yes, this has a typo.
   std::string verifyString;
-  ser.writeUTF(stringOne, &baseStream, false);
+  baseStream.write(stringOne, false);
 
-  ser.readUTF(verifyString, &baseStream, false);
+  baseStream.read(verifyString, false);
 
   REQUIRE(verifyString == stringOne);
 }
 
 TEST_CASE("TestWriteUTF2", "[MINIFI193]") {
-  org::apache::nifi::minifi::io::DataStream baseStream;
-
-  org::apache::nifi::minifi::io::Serializable ser;
+  org::apache::nifi::minifi::io::BufferStream baseStream;
 
   std::string stringOne = "hel\xa1o world";
   REQUIRE(11 == stringOne.length());
   std::string verifyString;
-  ser.writeUTF(stringOne, &baseStream, false);
+  baseStream.write(stringOne, false);
 
-  ser.readUTF(verifyString, &baseStream, false);
+  baseStream.read(verifyString, false);
 
   REQUIRE(verifyString == stringOne);
 }
 
 TEST_CASE("TestWriteUTF3", "[MINIFI193]") {
-  org::apache::nifi::minifi::io::DataStream baseStream;
-
-  org::apache::nifi::minifi::io::Serializable ser;
+  org::apache::nifi::minifi::io::BufferStream baseStream;
 
   std::string stringOne = "\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c";
   REQUIRE(12 == stringOne.length());
   std::string verifyString;
-  ser.writeUTF(stringOne, &baseStream, false);
+  baseStream.write(stringOne, false);
 
-  ser.readUTF(verifyString, &baseStream, false);
+  baseStream.read(verifyString, false);
 
   REQUIRE(verifyString == stringOne);
 }
-
-TEST_CASE("Serialization test: the byteSwap functions work correctly", "[byteSwap]") {
-    REQUIRE(byteSwap(uint16_t{0}) == uint16_t{0});
-    REQUIRE(byteSwap(uint16_t{0x0001}) == uint16_t{0x0100});
-    REQUIRE(byteSwap(uint16_t{0x0102}) == uint16_t{0x0201});
-    REQUIRE(byteSwap(uint16_t{0xFFEE}) == uint16_t{0xEEFF});
-
-    REQUIRE(byteSwap(uint32_t{0}) == uint32_t{0});
-    REQUIRE(byteSwap(uint32_t{0x00000001}) == uint32_t{0x01000000});
-    REQUIRE(byteSwap(uint32_t{0x01020304}) == uint32_t{0x04030201});
-    REQUIRE(byteSwap(uint32_t{0xFFEEDDCC}) == uint32_t{0xCCDDEEFF});
-
-    REQUIRE(byteSwap(uint64_t{0}) == uint64_t{0});
-    REQUIRE(byteSwap(uint64_t{0x0000000000000001}) == uint64_t{0x0100000000000000});
-    REQUIRE(byteSwap(uint64_t{0x0102030405060708}) == uint64_t{0x0807060504030201});
-    REQUIRE(byteSwap(uint64_t{0xFFEEDDCCBBAA9988}) == uint64_t{0x8899AABBCCDDEEFF});
-}
diff --git a/libminifi/test/unit/Site2SiteTests.cpp b/libminifi/test/unit/Site2SiteTests.cpp
index 66e0913..cd53528 100644
--- a/libminifi/test/unit/Site2SiteTests.cpp
+++ b/libminifi/test/unit/Site2SiteTests.cpp
@@ -32,7 +32,7 @@
 
 TEST_CASE("TestSetPortId", "[S2S1]") {
   std::unique_ptr<minifi::sitetosite::SiteToSitePeer> peer = std::unique_ptr<minifi::sitetosite::SiteToSitePeer>(
-      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<org::apache::nifi::minifi::io::DataStream>(new org::apache::nifi::minifi::io::DataStream()), "fake_host", 65433, ""));
+      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<org::apache::nifi::minifi::io::BufferStream>(new org::apache::nifi::minifi::io::BufferStream()), "fake_host", 65433, ""));
 
   minifi::sitetosite::RawSiteToSiteClient protocol(std::move(peer));
 
@@ -49,7 +49,7 @@
 
 TEST_CASE("TestSetPortIdUppercase", "[S2S2]") {
   std::unique_ptr<minifi::sitetosite::SiteToSitePeer> peer = std::unique_ptr<minifi::sitetosite::SiteToSitePeer>(
-      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<org::apache::nifi::minifi::io::DataStream>(new org::apache::nifi::minifi::io::DataStream()), "fake_host", 65433, ""));
+      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<org::apache::nifi::minifi::io::BufferStream>(new org::apache::nifi::minifi::io::BufferStream()), "fake_host", 65433, ""));
 
   minifi::sitetosite::RawSiteToSiteClient protocol(std::move(peer));
 
@@ -94,7 +94,7 @@
   sunny_path_bootstrap(collector);
 
   std::unique_ptr<minifi::sitetosite::SiteToSitePeer> peer = std::unique_ptr<minifi::sitetosite::SiteToSitePeer>(
-      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<minifi::io::DataStream>(new org::apache::nifi::minifi::io::BaseStream(collector)), "fake_host", 65433, ""));
+      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<minifi::io::BaseStream>(collector), "fake_host", 65433, ""));
 
   minifi::sitetosite::RawSiteToSiteClient protocol(std::move(peer));
 
@@ -163,7 +163,7 @@
   collector->push_response(resp_code);
 
   std::unique_ptr<minifi::sitetosite::SiteToSitePeer> peer = std::unique_ptr<minifi::sitetosite::SiteToSitePeer>(
-      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<minifi::io::DataStream>(new org::apache::nifi::minifi::io::BaseStream(collector)), "fake_host", 65433, ""));
+      new minifi::sitetosite::SiteToSitePeer(std::unique_ptr<minifi::io::BaseStream>(collector), "fake_host", 65433, ""));
 
   minifi::sitetosite::RawSiteToSiteClient protocol(std::move(peer));
 
diff --git a/libminifi/test/unit/SiteToSiteHelper.h b/libminifi/test/unit/SiteToSiteHelper.h
index e17788d..693ec31 100644
--- a/libminifi/test/unit/SiteToSiteHelper.h
+++ b/libminifi/test/unit/SiteToSiteHelper.h
@@ -19,7 +19,7 @@
 #define LIBMINIFI_TEST_UNIT_SITE2SITE_HELPER_H_
 
 #include <queue>
-#include "io/BaseStream.h"
+#include "io/BufferStream.h"
 #include "io/EndianCheck.h"
 #include "core/Core.h"
 /**
@@ -27,34 +27,24 @@
  */
 class SiteToSiteResponder : public minifi::io::BaseStream {
  private:
-  std::queue<std::string> server_responses_;
+  minifi::io::BufferStream server_responses_;
   std::queue<std::string> client_responses_;
  public:
   SiteToSiteResponder() = default;
   // initialize
-  virtual short initialize() {
+  int initialize() override {
     return 1;
   }
 
-  void push_response(std::string resp) {
-    server_responses_.push(resp);
+  void push_response(const std::string& resp) {
+    server_responses_.write(reinterpret_cast<const uint8_t*>(resp.data()), resp.length());
   }
 
-  std::string get_next_response() {
-    std::string ret = server_responses_.front();
-    server_responses_.pop();
-    return ret;
-  }
-
-  int writeData(uint8_t *value, int size) {
-    client_responses_.push(std::string((char*) value, size));
+  int write(const uint8_t *value, int size) override {
+    client_responses_.push(std::string(reinterpret_cast<const char*>(value), size));
     return size;
   }
 
-  bool has_next_client_response() {
-    return !client_responses_.empty();
-  }
-
   std::string get_next_client_response() {
     std::string ret = client_responses_.front();
     client_responses_.pop();
@@ -62,89 +52,13 @@
   }
 
   /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(uint8_t &value) {
-    value = get_next_response().c_str()[0];
-    return 1;
-  }
-
-  /**
-   * reads two bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(uint16_t &base_value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    base_value = std::stoi(get_next_response());
-    return 2;
-  }
-
-  /**
-   * reads a byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(char &value) {
-    value = get_next_response().c_str()[0];
-    return 1;
-  }
-
-  /**
    * reads a byte array from the stream
    * @param value reference in which will set the result
    * @param len length to read
-   * @param stream stream from which we will read
    * @return resulting read size
    **/
-  virtual int read(uint8_t *value, int len) {
-    std::string str = get_next_response();
-    memcpy(value, str.c_str(), str.size());
-    return len;
-  }
-
-  virtual int readData(uint8_t *buf, int buflen) {
-    std::string str = get_next_response();
-    memset(buf, 0x00, buflen);
-    memcpy(buf, str.c_str(), str.size());
-    return str.size();
-  }
-
-  /**
-   * reads four bytes from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(uint32_t &value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    value = std::stoul(get_next_response());
-    return 4;
-  }
-
-  /**
-   * reads eight byte from the stream
-   * @param value reference in which will set the result
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int read(uint64_t &value, bool is_little_endian = minifi::io::EndiannessCheck::IS_LITTLE) {
-    value = std::stoull(get_next_response());
-    return 8;
-  }
-
-  /**
-   * read UTF from stream
-   * @param str reference string
-   * @param stream stream from which we will read
-   * @return resulting read size
-   **/
-  virtual int readUTF(std::string &str, bool widen = false) {
-    str = get_next_response();
-    return str.length();
+  int read(uint8_t *value, int len) override {
+    return server_responses_.read(value, len);
   }
 
 };
diff --git a/libminifi/test/unit/SocketTests.cpp b/libminifi/test/unit/SocketTests.cpp
index bae9bf6..d069358 100644
--- a/libminifi/test/unit/SocketTests.cpp
+++ b/libminifi/test/unit/SocketTests.cpp
@@ -33,21 +33,21 @@
   org::apache::nifi::minifi::io::Socket socket(std::make_shared<org::apache::nifi::minifi::io::SocketContext>(std::make_shared<minifi::Configure>()), Sockets::getMyHostName(), 8183);
   REQUIRE(-1 == socket.initialize());
   REQUIRE(socket.getHostname().rfind(Sockets::getMyHostName(), 0) == 0);
-  socket.closeStream();
+  socket.close();
 }
 
 TEST_CASE("TestSocketWriteTest1", "[TestSocket2]") {
   org::apache::nifi::minifi::io::Socket socket(std::make_shared<org::apache::nifi::minifi::io::SocketContext>(std::make_shared<minifi::Configure>()), Sockets::getMyHostName(), 8183);
   REQUIRE(-1 == socket.initialize());
 
-  socket.writeData(0, 0);
+  socket.write((const uint8_t*)nullptr, 0);
 
   std::vector<uint8_t> buffer;
   buffer.push_back('a');
 
-  REQUIRE(-1 == socket.writeData(buffer, 1));
+  REQUIRE(-1 == socket.write(buffer, 1));
 
-  socket.closeStream();
+  socket.close();
 }
 
 TEST_CASE("TestSocketWriteTest2", "[TestSocket3]") {
@@ -62,18 +62,18 @@
 
   REQUIRE(-1 != client.initialize());
 
-  REQUIRE(1 == client.writeData(buffer, 1));
+  REQUIRE(1 == client.write(buffer, 1));
 
   std::vector<uint8_t> readBuffer;
   readBuffer.resize(1);
 
-  REQUIRE(1 == server.readData(readBuffer, 1));
+  REQUIRE(1 == server.read(readBuffer, 1));
 
   REQUIRE(readBuffer == buffer);
 
-  server.closeStream();
+  server.close();
 
-  client.closeStream();
+  client.close();
 }
 
 TEST_CASE("TestGetHostName", "[TestSocket4]") {
@@ -101,9 +101,9 @@
 
   REQUIRE(negative_two == negative_one);
 
-  server.closeStream();
+  server.close();
 
-  client.closeStream();
+  client.close();
 }
 
 TEST_CASE("TestWriteEndian32", "[TestSocket6]") {
@@ -136,9 +136,9 @@
 
     REQUIRE(negative_two == negative_one);
   }
-  server.closeStream();
+  server.close();
 
-  client.closeStream();
+  client.close();
 }
 
 TEST_CASE("TestSocketWriteTestAfterClose", "[TestSocket7]") {
@@ -155,20 +155,20 @@
 
   REQUIRE(-1 != client.initialize());
 
-  REQUIRE(1 == client.writeData(buffer, 1));
+  REQUIRE(1 == client.write(buffer, 1));
 
   std::vector<uint8_t> readBuffer;
   readBuffer.resize(1);
 
-  REQUIRE(1 == server.readData(readBuffer, 1));
+  REQUIRE(1 == server.read(readBuffer, 1));
 
   REQUIRE(readBuffer == buffer);
 
-  client.closeStream();
+  client.close();
 
-  REQUIRE(-1 == client.writeData(buffer, 1));
+  REQUIRE(-1 == client.write(buffer, 1));
 
-  server.closeStream();
+  server.close();
 }
 
 #ifdef OPENSSL_ENABLED
diff --git a/libminifi/test/unit/StreamTests.cpp b/libminifi/test/unit/StreamTests.cpp
index 6c2f6a6..99bd92f 100644
--- a/libminifi/test/unit/StreamTests.cpp
+++ b/libminifi/test/unit/StreamTests.cpp
@@ -27,19 +27,15 @@
 #include "io/BaseStream.h"
 
 TEST_CASE("TestReadData", "[testread]") {
-  auto base = std::make_shared<minifi::io::BaseStream>();
-  uint64_t b = 8;
-  base->write(b);
+  auto base = std::make_shared<minifi::io::BufferStream>();
+  base->write((const uint8_t*)"\x01\x02\x03\x04\x05\x06\x07\x08", 8);
   uint64_t c = 0;
-  REQUIRE(8 == base->readData(reinterpret_cast<uint8_t*>(&c), 8));
-  if (minifi::io::EndiannessCheck::IS_LITTLE)
-    REQUIRE(c == 576460752303423488);
-  else
-    REQUIRE(c == 8);
+  REQUIRE(8 == base->read(c));
+  REQUIRE(c == 0x0102030405060708);
 }
 
 TEST_CASE("TestRead8", "[testread]") {
-  auto base = std::make_shared<minifi::io::BaseStream>();
+  auto base = std::make_shared<minifi::io::BufferStream>();
   uint64_t b = 8;
   base->write(b);
   uint64_t c = 0;
@@ -48,7 +44,7 @@
 }
 
 TEST_CASE("TestRead2", "[testread]") {
-  auto base = std::make_shared<minifi::io::BaseStream>();
+  auto base = std::make_shared<minifi::io::BufferStream>();
   uint16_t b = 8;
   base->write(b);
   uint16_t c = 0;
@@ -57,7 +53,7 @@
 }
 
 TEST_CASE("TestRead1", "[testread]") {
-  auto base = std::make_shared<minifi::io::BaseStream>();
+  auto base = std::make_shared<minifi::io::BufferStream>();
   uint8_t b = 8;
   base->write(&b, 1);
   uint8_t c = 0;
@@ -66,10 +62,18 @@
 }
 
 TEST_CASE("TestRead4", "[testread]") {
-  auto base = std::make_shared<minifi::io::BaseStream>();
+  auto base = std::make_shared<minifi::io::BufferStream>();
   uint32_t b = 8;
   base->write(b);
   uint32_t c = 0;
   base->read(c);
   REQUIRE(c == 8);
 }
+
+TEST_CASE("TestWrite1", "[testwrite]") {
+  auto base = std::make_shared<minifi::io::BufferStream>();
+  base->write((uint64_t)0x0102030405060708);
+  std::string bytes(8, '\0');
+  REQUIRE(8 == base->read(reinterpret_cast<uint8_t*>(const_cast<char*>(bytes.data())), 8));
+  REQUIRE(bytes == "\x01\x02\x03\x04\x05\x06\x07\x08");
+}
diff --git a/libminifi/test/unit/ZlibStreamTests.cpp b/libminifi/test/unit/ZlibStreamTests.cpp
index 4069d79..7a81f06 100644
--- a/libminifi/test/unit/ZlibStreamTests.cpp
+++ b/libminifi/test/unit/ZlibStreamTests.cpp
@@ -27,7 +27,8 @@
 
 TEST_CASE("gzip compression and decompression", "[basic]") {
   /* Compression*/
-  io::ZlibCompressStream compressStream;
+  io::BufferStream compressBuffer;
+  io::ZlibCompressStream compressStream(gsl::make_not_null(&compressBuffer));
 
   std::string original;
   SECTION("Empty") {
@@ -53,38 +54,40 @@
     }
   }
 
-  compressStream.closeStream();
+  compressStream.close();
 
-  REQUIRE(0U < compressStream.getSize());
+  REQUIRE(0U < compressBuffer.size());
 
-  if (compressStream.getSize() < 64U) {
-    std::cerr << utils::StringUtils::to_hex(compressStream.getBuffer(), compressStream.getSize()) << std::endl;
+  if (compressBuffer.size() < 64U) {
+    std::cerr << utils::StringUtils::to_hex(compressBuffer.getBuffer(), compressBuffer.size()) << std::endl;
   }
 
   /* Decompression */
-  io::ZlibDecompressStream decompressStream;
+  io::BufferStream decompressBuffer;
+  io::ZlibDecompressStream decompressStream(gsl::make_not_null(&decompressBuffer));
 
-  decompressStream.writeData(const_cast<uint8_t*>(compressStream.getBuffer()), compressStream.getSize());
+  decompressStream.write(const_cast<uint8_t*>(compressBuffer.getBuffer()), compressBuffer.size());
 
   REQUIRE(decompressStream.isFinished());
-  REQUIRE(original == std::string(reinterpret_cast<const char*>(decompressStream.getBuffer()), decompressStream.getSize()));
+  REQUIRE(original == std::string(reinterpret_cast<const char*>(decompressBuffer.getBuffer()), decompressBuffer.size()));
 }
 
 TEST_CASE("gzip compression and decompression pipeline", "[basic]") {
-  io::ZlibDecompressStream decompressStream;
-  io::ZlibCompressStream compressStream(&decompressStream);
+  io::BufferStream output;
+  io::ZlibDecompressStream decompressStream(gsl::make_not_null(&output));
+  io::ZlibCompressStream compressStream(gsl::make_not_null(&decompressStream));
 
   std::string original;
   SECTION("Empty") {
   }
   SECTION("Simple content in one write") {
-    REQUIRE(strlen("foobar") == compressStream.writeData(reinterpret_cast<uint8_t*>(const_cast<char*>("foobar")), strlen("foobar")));
+    REQUIRE(strlen("foobar") == compressStream.write(reinterpret_cast<uint8_t*>(const_cast<char*>("foobar")), strlen("foobar")));
     original += "foobar";
   }
   SECTION("Simple content in two writes") {
-    REQUIRE(strlen("foo") == compressStream.writeData(reinterpret_cast<uint8_t*>(const_cast<char*>("foo")), strlen("foo")));
+    REQUIRE(strlen("foo") == compressStream.write(reinterpret_cast<uint8_t*>(const_cast<char*>("foo")), strlen("foo")));
     original += "foo";
-    REQUIRE(strlen("bar") == compressStream.writeData(reinterpret_cast<uint8_t*>(const_cast<char*>("bar")), strlen("bar")));
+    REQUIRE(strlen("bar") == compressStream.write(reinterpret_cast<uint8_t*>(const_cast<char*>("bar")), strlen("bar")));
     original += "bar";
   }
   SECTION("Large data") {
@@ -94,12 +97,12 @@
     for (size_t i = 0U; i < 1024U; i++) {
       std::generate(buf.begin(), buf.end(), [&](){return dist(gen);});
       original += std::string(reinterpret_cast<const char*>(buf.data()), buf.size());
-      REQUIRE(buf.size() == compressStream.writeData(buf.data(), buf.size()));
+      REQUIRE(buf.size() == compressStream.write(buf.data(), buf.size()));
     }
   }
 
-  compressStream.closeStream();
+  compressStream.close();
 
   REQUIRE(decompressStream.isFinished());
-  REQUIRE(original == std::string(reinterpret_cast<const char*>(decompressStream.getBuffer()), decompressStream.getSize()));
+  REQUIRE(original == std::string(reinterpret_cast<const char*>(output.getBuffer()), output.size()));
 }
diff --git a/nanofi/include/core/cxxstructs.h b/nanofi/include/core/cxxstructs.h
index 63978bf..c208683 100644
--- a/nanofi/include/core/cxxstructs.h
+++ b/nanofi/include/core/cxxstructs.h
@@ -21,7 +21,7 @@
 
 #include "cstructs.h"
 #include "cxx/Plan.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 
 struct flow : public ExecutionPlan {
   using ExecutionPlan::ExecutionPlan;
diff --git a/nanofi/include/cxx/Instance.h b/nanofi/include/cxx/Instance.h
index c8347c7..e9c5721 100644
--- a/nanofi/include/cxx/Instance.h
+++ b/nanofi/include/cxx/Instance.h
@@ -131,7 +131,7 @@
     return content_repo_;
   }
 
-  void transfer(const std::shared_ptr<FlowFileRecord> &ff, const std::shared_ptr<minifi::io::DataStream> &stream = nullptr) {
+  void transfer(const std::shared_ptr<FlowFileRecord> &ff, const std::shared_ptr<minifi::io::BufferStream> &stream = nullptr) {
     auto processContext = std::make_shared<core::ProcessContext>(proc_node_, nullptr, no_op_repo_, no_op_repo_, configure_, content_repo_);
     auto sessionFactory = std::make_shared<core::ProcessSessionFactory>(processContext);
 
diff --git a/nanofi/include/cxx/Plan.h b/nanofi/include/cxx/Plan.h
index 152d65b..fedb65f 100644
--- a/nanofi/include/cxx/Plan.h
+++ b/nanofi/include/cxx/Plan.h
@@ -53,7 +53,7 @@
 using content_repo_sptr = std::shared_ptr<core::ContentRepository>;
 
 struct flowfile_input_params {
-  std::shared_ptr<minifi::io::DataStream> content_stream;
+  std::shared_ptr<minifi::io::BaseStream> content_stream;
   std::map<std::string, std::string> attributes;
 };
 
diff --git a/nanofi/src/api/nanofi.cpp b/nanofi/src/api/nanofi.cpp
index db65427..52c9939 100644
--- a/nanofi/src/api/nanofi.cpp
+++ b/nanofi/src/api/nanofi.cpp
@@ -31,7 +31,7 @@
 #include "ResourceClaim.h"
 #include "core/logging/LoggerConfiguration.h"
 #include "utils/StringUtils.h"
-#include "io/DataStream.h"
+#include "io/BufferStream.h"
 #include "core/cxxstructs.h"
 
 using string_map = std::map<std::string, std::string>;
@@ -487,7 +487,7 @@
   auto content_repo = minifi_instance_ref->getContentRepository();
 
   std::shared_ptr<minifi::ResourceClaim> claim = nullptr;
-  std::shared_ptr<minifi::io::DataStream> stream = nullptr;  // Used when content is not in content repo
+  std::shared_ptr<minifi::io::BufferStream> stream = nullptr;  // Used when content is not in content repo
 
   if(ff->contentLocation) {
     auto ff_content_repo_ptr = (static_cast<std::shared_ptr<minifi::core::ContentRepository>*>(ff->crp));
@@ -498,13 +498,13 @@
       claim->increaseFlowFileRecordOwnedCount();
     } else {
       file_buffer fb = file_to_buffer(ff->contentLocation);
-      stream = std::make_shared<minifi::io::DataStream>();
-      stream->writeData(fb.buffer, gsl::narrow<int>(fb.file_len));
+      stream = std::make_shared<minifi::io::BufferStream>();
+      stream->write(fb.buffer, gsl::narrow<int>(fb.file_len));
       free(fb.buffer);
     }
   } else {
     // The flowfile has no content - create an empty stream to create empty content
-    stream = std::make_shared<minifi::io::DataStream>();
+    stream = std::make_shared<minifi::io::BufferStream>();
   }
 
   auto ffr = std::make_shared<minifi::FlowFileRecord>(no_op, content_repo, attribute_map, claim);
@@ -701,9 +701,9 @@
                                                                                              *content_repo);
       ff_data->content_stream = (*content_repo)->read(*claim);
     } else {
-      ff_data->content_stream = std::make_shared<minifi::io::DataStream>();
+      ff_data->content_stream = std::make_shared<minifi::io::BufferStream>();
       file_buffer fb = file_to_buffer(input_ff->contentLocation);
-      ff_data->content_stream->writeData(fb.buffer, gsl::narrow<int>(fb.file_len));
+      ff_data->content_stream->write(fb.buffer, gsl::narrow<int>(fb.file_len));
       free(fb.buffer);
     }
 
@@ -729,8 +729,8 @@
   plan->reset();
 
   auto ff_data = std::make_shared<flowfile_input_params>();
-  ff_data->content_stream = std::make_shared<minifi::io::DataStream>();
-  ff_data->content_stream->writeData(buf, gsl::narrow<int>(size));
+  ff_data->content_stream = std::make_shared<minifi::io::BufferStream>();
+  ff_data->content_stream->write(buf, gsl::narrow<int>(size));
 
   plan->runNextProcessor(nullptr, ff_data);
   while (plan->runNextProcessor()) {
diff --git a/nanofi/tests/CSite2SiteTests.cpp b/nanofi/tests/CSite2SiteTests.cpp
index 60a9326..a3d48ba 100644
--- a/nanofi/tests/CSite2SiteTests.cpp
+++ b/nanofi/tests/CSite2SiteTests.cpp
@@ -97,27 +97,27 @@
 void accept_transfer(minifi::io::BaseStream* stream, const std::string& crcstr, TransferState& transfer_state, S2SReceivedData& s2s_data) {
   // In long term it would be nice to calculate the crc of the received data here
   send_response_code(stream, 12);  // confirmed
-  stream->writeUTF(crcstr);
+  stream->write(crcstr);
   send_response_code(stream, 13);  // transaction finished
 
   wait_until(transfer_state.transer_completed);
 
   std::string requesttype;
-  stream->readUTF(requesttype);
+  stream->read(requesttype);
 
   if(requesttype == "SEND_FLOWFILES") {
     s2s_data.request_type_ok = true;
     stream->read(s2s_data.attr_num);
     std::string key, value;
     for(int i = 0; i < s2s_data.attr_num; ++i) {
-      stream->readUTF(key, true);
-      stream->readUTF(value, true);
+      stream->read(key, true);
+      stream->read(value, true);
       s2s_data.attributes[key] = value;
     }
     uint64_t content_size=0;
     stream->read(content_size);
     s2s_data.payload.resize(content_size);
-    stream->readData(s2s_data.payload, content_size);
+    stream->read(s2s_data.payload, content_size);
   } else {
     s2s_data.request_type_ok = false;
   }
@@ -127,7 +127,7 @@
 void sunny_path_bootstrap(minifi::io::BaseStream* stream, TransferState& transfer_state, S2SReceivedData& s2s_data) {
   // Verify the magic string
   char c_array[4];
-  stream->readData((uint8_t*)c_array, 4);
+  stream->read((uint8_t*)c_array, 4);
   s2s_data.magic_string = std::string(c_array, 4);
   uint8_t success = 0x14;
   stream->write(&success, 1);
@@ -139,7 +139,7 @@
   int read_len = 0;
   while(!found_codec) {
     uint8_t handshake_data[1000];
-    int actual_len = stream->readData(handshake_data+read_len, 1000-read_len);
+    int actual_len = stream->read(handshake_data+read_len, 1000-read_len);
     if(actual_len <= 0) {
       continue;
     }