This is an automated email from the ASF dual-hosted git repository.
sgilmore pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new d261a824f4 GH-42146: [MATLAB] Add IPC `RecordBatchFileReader` and
`RecordBatchFileWriter` MATLAB classes (#42201)
d261a824f4 is described below
commit d261a824f4e322e6dcc01948c3a2769690d11b3d
Author: Sarah Gilmore <[email protected]>
AuthorDate: Thu Jun 20 09:21:48 2024 -0400
GH-42146: [MATLAB] Add IPC `RecordBatchFileReader` and
`RecordBatchFileWriter` MATLAB classes (#42201)
### Rationale for this change
To enable initial IPC I/O support in the MATLAB interface, we should add a
`RecordBatchFileReader` class and a `RecordBatchFileWriter` class.
### What changes are included in this PR?
1. Added a new `arrow.io.ipc.RecordBatchFileWriter` class.
2. Added a new `arrow.io.ipc.RecordBatchFileReader` class.
**Example**
```matlab
>> city = ["Boston" "Seattle" "Denver" "Juno" "Anchorage" "Chicago"]';
>> daylength = duration(["15:17:01" "15:59:16" "14:59:14" "19:21:23"
"14:18:24" "15:13:39"])';
>> matlabTable = table(city, daylength, VariableNames=["City",
"DayLength"]);
>> recordBatch1 = arrow.recordBatch(matlabTable(1:4, :))
>> recordBatch2 = arrow.recordBatch(matlabTable(5:end, :));
>> writer = arrow.io.ipc.RecordBatchFileWriter("daylight.arrow",
recordBatch1.Schema);
>> writer.writeRecordBatch(recordBatch1);
>> writer.writeRecordBatch(recordBatch2);
>> writer.close();
>> reader = arrow.io.ipc.RecordBatchFileReader("daylight.arrow");
reader =
RecordBatchFileReader with properties:
NumRecordBatches: 2
Schema: [1×1 arrow.tabular.Schema]
>> reader.Schema
ans =
Arrow Schema with 2 fields:
City: String | DayLength: Time64
>> rb1 = reader.read(1);
>> isequal(rb1, recordBatch1)
ans =
logical
1
>> rb2 = reader.read(2);
>> isequal(rb2, recordBatch2)
ans =
logical
1
```
### Are these changes tested?
Yes. Added two new test files:
1. `arrow/matlab/test/io/ipc/tRecordBatchFileWriter.m`
2. `arrow/matlab/test/io/ipc/tRecordBatchFileReader.m`
### Are there any user-facing changes?
Yes. Users can now serialize `RecordBatch`es and `Table`s to files using
the Arrow IPC data format as well as read in `RecordBatch`es from Arrow IPC
data files.
### Future Directions
1. Add `RecordBatchStreamWriter` and `RecordBatchStreamReader`
2. Expose options for
[controlling](https://github.com/apache/arrow/blob/main/cpp/src/arrow/ipc/options.h)
IPC reading and writing in MATLAB.
3. Add more methods to `RecordBatchFileReader` to read in multiple record
batches at once as well as importing the data as an Arrow `Table`.
* GitHub Issue: #42146
Authored-by: Sarah Gilmore <[email protected]>
Signed-off-by: Sarah Gilmore <[email protected]>
---
matlab/src/cpp/arrow/matlab/error/error.h | 7 +
.../io/ipc/proxy/record_batch_file_reader.cc | 128 +++++++++++++
.../matlab/io/ipc/proxy/record_batch_file_reader.h | 44 +++++
.../io/ipc/proxy/record_batch_file_writer.cc | 107 +++++++++++
.../matlab/io/ipc/proxy/record_batch_file_writer.h | 42 ++++
matlab/src/cpp/arrow/matlab/proxy/factory.cc | 4 +
.../matlab/+arrow/+io/+ipc/RecordBatchFileReader.m | 64 +++++++
.../matlab/+arrow/+io/+ipc/RecordBatchFileWriter.m | 77 ++++++++
matlab/test/arrow/io/ipc/tRecordBatchFileReader.m | 184 ++++++++++++++++++
matlab/test/arrow/io/ipc/tRecordBatchFileWriter.m | 211 +++++++++++++++++++++
matlab/tools/cmake/BuildMatlabArrowInterface.cmake | 4 +-
11 files changed, 871 insertions(+), 1 deletion(-)
diff --git a/matlab/src/cpp/arrow/matlab/error/error.h
b/matlab/src/cpp/arrow/matlab/error/error.h
index 58c43d8843..e5a5df6f4b 100644
--- a/matlab/src/cpp/arrow/matlab/error/error.h
+++ b/matlab/src/cpp/arrow/matlab/error/error.h
@@ -242,5 +242,12 @@ static const char*
ARRAY_SLICE_FAILED_TO_CREATE_ARRAY_PROXY =
"arrow:array:slice:FailedToCreateArrayProxy";
static const char* C_EXPORT_FAILED = "arrow:c:export:ExportFailed";
static const char* C_IMPORT_FAILED = "arrow:c:import:ImportFailed";
+static const char* IPC_RECORD_BATCH_WRITE_FAILED =
+ "arrow:io:ipc:FailedToWriteRecordBatch";
+static const char* IPC_RECORD_BATCH_WRITE_CLOSE_FAILED =
"arrow:io:ipc:CloseFailed";
+static const char* IPC_RECORD_BATCH_READER_OPEN_FAILED =
+ "arrow:io:ipc:FailedToOpenRecordBatchReader";
+static const char* IPC_RECORD_BATCH_READ_INVALID_INDEX =
"arrow:io:ipc:InvalidIndex";
+static const char* IPC_RECORD_BATCH_READ_FAILED = "arrow:io:ipc:ReadFailed";
} // namespace arrow::matlab::error
diff --git
a/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.cc
b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.cc
new file mode 100644
index 0000000000..9db5d6a9ba
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.cc
@@ -0,0 +1,128 @@
+// 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 "arrow/matlab/io/ipc/proxy/record_batch_file_reader.h"
+#include "arrow/io/file.h"
+#include "arrow/matlab/error/error.h"
+#include "arrow/matlab/tabular/proxy/record_batch.h"
+#include "arrow/matlab/tabular/proxy/schema.h"
+#include "arrow/util/utf8.h"
+
+#include "libmexclass/proxy/ProxyManager.h"
+
+namespace arrow::matlab::io::ipc::proxy {
+
+namespace {
+libmexclass::error::Error makeInvalidNumericIndexError(const int32_t
matlab_index,
+ const int32_t
num_batches) {
+ std::stringstream error_message_stream;
+ error_message_stream << "Invalid record batch index: ";
+ error_message_stream << matlab_index;
+ error_message_stream
+ << ". Record batch index must be between 1 and the number of record
batches (";
+ error_message_stream << num_batches;
+ error_message_stream << ").";
+ return libmexclass::error::Error{error::IPC_RECORD_BATCH_READ_INVALID_INDEX,
+ error_message_stream.str()};
+}
+} // namespace
+
+RecordBatchFileReader::RecordBatchFileReader(
+ const std::shared_ptr<arrow::ipc::RecordBatchFileReader> reader)
+ : reader{std::move(reader)} {
+ REGISTER_METHOD(RecordBatchFileReader, getNumRecordBatches);
+ REGISTER_METHOD(RecordBatchFileReader, getSchema);
+ REGISTER_METHOD(RecordBatchFileReader, readRecordBatchAtIndex);
+}
+
+libmexclass::proxy::MakeResult RecordBatchFileReader::make(
+ const libmexclass::proxy::FunctionArguments& constructor_arguments) {
+ namespace mda = ::matlab::data;
+ using RecordBatchFileReaderProxy =
arrow::matlab::io::ipc::proxy::RecordBatchFileReader;
+
+ const mda::StructArray opts = constructor_arguments[0];
+
+ const mda::StringArray filename_mda = opts[0]["Filename"];
+ const auto filename_utf16 = std::u16string(filename_mda[0]);
+ MATLAB_ASSIGN_OR_ERROR(const auto filename_utf8,
+ arrow::util::UTF16StringToUTF8(filename_utf16),
+ error::UNICODE_CONVERSION_ERROR_ID);
+
+ MATLAB_ASSIGN_OR_ERROR(auto input_stream,
arrow::io::ReadableFile::Open(filename_utf8),
+ error::FAILED_TO_OPEN_FILE_FOR_WRITE);
+
+ MATLAB_ASSIGN_OR_ERROR(auto reader,
+ arrow::ipc::RecordBatchFileReader::Open(input_stream),
+ error::IPC_RECORD_BATCH_READER_OPEN_FAILED);
+
+ return std::make_shared<RecordBatchFileReaderProxy>(std::move(reader));
+}
+
+void RecordBatchFileReader::getNumRecordBatches(
+ libmexclass::proxy::method::Context& context) {
+ namespace mda = ::matlab::data;
+
+ mda::ArrayFactory factory;
+ const auto num_batches = reader->num_record_batches();
+ context.outputs[0] = factory.createScalar(num_batches);
+}
+
+void RecordBatchFileReader::getSchema(libmexclass::proxy::method::Context&
context) {
+ namespace mda = ::matlab::data;
+ using SchemaProxy = arrow::matlab::tabular::proxy::Schema;
+
+ auto schema = reader->schema();
+
+ auto schema_proxy = std::make_shared<SchemaProxy>(std::move(schema));
+ const auto schema_proxy_id =
+ libmexclass::proxy::ProxyManager::manageProxy(schema_proxy);
+
+ mda::ArrayFactory factory;
+ const auto schema_proxy_id_mda = factory.createScalar(schema_proxy_id);
+ context.outputs[0] = schema_proxy_id_mda;
+}
+
+void RecordBatchFileReader::readRecordBatchAtIndex(
+ libmexclass::proxy::method::Context& context) {
+ namespace mda = ::matlab::data;
+ using RecordBatchProxy = arrow::matlab::tabular::proxy::RecordBatch;
+
+ mda::StructArray opts = context.inputs[0];
+ const mda::TypedArray<int32_t> matlab_index_mda = opts[0]["Index"];
+
+ const auto matlab_index = matlab_index_mda[0];
+ const auto num_record_batches = reader->num_record_batches();
+ if (matlab_index < 1 || matlab_index > num_record_batches) {
+ context.error = makeInvalidNumericIndexError(matlab_index,
num_record_batches);
+ return;
+ }
+ const auto arrow_index = matlab_index - 1;
+
+ MATLAB_ASSIGN_OR_ERROR_WITH_CONTEXT(const auto record_batch,
+ reader->ReadRecordBatch(arrow_index),
context,
+ error::IPC_RECORD_BATCH_READ_FAILED);
+
+ auto record_batch_proxy =
std::make_shared<RecordBatchProxy>(std::move(record_batch));
+ const auto record_batch_proxy_id =
+ libmexclass::proxy::ProxyManager::manageProxy(record_batch_proxy);
+
+ mda::ArrayFactory factory;
+ const auto record_batch_proxyy_id_mda =
factory.createScalar(record_batch_proxy_id);
+ context.outputs[0] = record_batch_proxyy_id_mda;
+}
+
+} // namespace arrow::matlab::io::ipc::proxy
\ No newline at end of file
diff --git
a/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.h
b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.h
new file mode 100644
index 0000000000..41d5c9a158
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.h
@@ -0,0 +1,44 @@
+// 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 "arrow/ipc/reader.h"
+#include "libmexclass/proxy/Proxy.h"
+
+namespace arrow::matlab::io::ipc::proxy {
+
+class RecordBatchFileReader : public libmexclass::proxy::Proxy {
+ public:
+ RecordBatchFileReader(std::shared_ptr<arrow::ipc::RecordBatchFileReader>
reader);
+
+ ~RecordBatchFileReader() = default;
+
+ static libmexclass::proxy::MakeResult make(
+ const libmexclass::proxy::FunctionArguments& constructor_arguments);
+
+ protected:
+ std::shared_ptr<arrow::ipc::RecordBatchFileReader> reader;
+
+ void getNumRecordBatches(libmexclass::proxy::method::Context& context);
+
+ void getSchema(libmexclass::proxy::method::Context& context);
+
+ void readRecordBatchAtIndex(libmexclass::proxy::method::Context& context);
+};
+
+} // namespace arrow::matlab::io::ipc::proxy
\ No newline at end of file
diff --git
a/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.cc
b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.cc
new file mode 100644
index 0000000000..ed1052e0a8
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.cc
@@ -0,0 +1,107 @@
+// 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 "arrow/matlab/io/ipc/proxy/record_batch_file_writer.h"
+#include "arrow/io/file.h"
+#include "arrow/matlab/error/error.h"
+#include "arrow/matlab/tabular/proxy/record_batch.h"
+#include "arrow/matlab/tabular/proxy/schema.h"
+#include "arrow/matlab/tabular/proxy/table.h"
+#include "arrow/util/utf8.h"
+
+#include "libmexclass/proxy/ProxyManager.h"
+
+namespace arrow::matlab::io::ipc::proxy {
+
+RecordBatchFileWriter::RecordBatchFileWriter(
+ const std::shared_ptr<arrow::ipc::RecordBatchWriter> writer)
+ : writer{std::move(writer)} {
+ REGISTER_METHOD(RecordBatchFileWriter, close);
+ REGISTER_METHOD(RecordBatchFileWriter, writeRecordBatch);
+ REGISTER_METHOD(RecordBatchFileWriter, writeTable);
+}
+
+libmexclass::proxy::MakeResult RecordBatchFileWriter::make(
+ const libmexclass::proxy::FunctionArguments& constructor_arguments) {
+ namespace mda = ::matlab::data;
+ using RecordBatchFileWriterProxy =
arrow::matlab::io::ipc::proxy::RecordBatchFileWriter;
+ using SchemaProxy = arrow::matlab::tabular::proxy::Schema;
+
+ const mda::StructArray opts = constructor_arguments[0];
+
+ const mda::StringArray filename_mda = opts[0]["Filename"];
+ const auto filename_utf16 = std::u16string(filename_mda[0]);
+ MATLAB_ASSIGN_OR_ERROR(const auto filename_utf8,
+ arrow::util::UTF16StringToUTF8(filename_utf16),
+ error::UNICODE_CONVERSION_ERROR_ID);
+
+ const mda::TypedArray<uint64_t> arrow_schema_proxy_id_mda =
opts[0]["SchemaProxyID"];
+ auto proxy =
libmexclass::proxy::ProxyManager::getProxy(arrow_schema_proxy_id_mda[0]);
+ auto arrow_schema_proxy = std::static_pointer_cast<SchemaProxy>(proxy);
+ auto arrow_schema = arrow_schema_proxy->unwrap();
+
+ MATLAB_ASSIGN_OR_ERROR(auto output_stream,
+ arrow::io::FileOutputStream::Open(filename_utf8),
+ error::FAILED_TO_OPEN_FILE_FOR_WRITE);
+
+ MATLAB_ASSIGN_OR_ERROR(auto writer,
+ arrow::ipc::MakeFileWriter(output_stream,
arrow_schema),
+ "arrow:matlab:MakeFailed");
+
+ return std::make_shared<RecordBatchFileWriterProxy>(std::move(writer));
+}
+
+void RecordBatchFileWriter::writeRecordBatch(
+ libmexclass::proxy::method::Context& context) {
+ namespace mda = ::matlab::data;
+ using RecordBatchProxy = ::arrow::matlab::tabular::proxy::RecordBatch;
+
+ mda::StructArray opts = context.inputs[0];
+ const mda::TypedArray<uint64_t> record_batch_proxy_id_mda =
+ opts[0]["RecordBatchProxyID"];
+ const uint64_t record_batch_proxy_id = record_batch_proxy_id_mda[0];
+
+ auto proxy =
libmexclass::proxy::ProxyManager::getProxy(record_batch_proxy_id);
+ auto record_batch_proxy = std::static_pointer_cast<RecordBatchProxy>(proxy);
+ auto record_batch = record_batch_proxy->unwrap();
+
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(writer->WriteRecordBatch(*record_batch),
context,
+ error::IPC_RECORD_BATCH_WRITE_FAILED);
+}
+
+void RecordBatchFileWriter::writeTable(libmexclass::proxy::method::Context&
context) {
+ namespace mda = ::matlab::data;
+ using TableProxy = ::arrow::matlab::tabular::proxy::Table;
+
+ mda::StructArray opts = context.inputs[0];
+ const mda::TypedArray<uint64_t> table_proxy_id_mda = opts[0]["TableProxyID"];
+ const uint64_t table_proxy_id = table_proxy_id_mda[0];
+
+ auto proxy = libmexclass::proxy::ProxyManager::getProxy(table_proxy_id);
+ auto table_proxy = std::static_pointer_cast<TableProxy>(proxy);
+ auto table = table_proxy->unwrap();
+
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(writer->WriteTable(*table), context,
+ error::IPC_RECORD_BATCH_WRITE_FAILED);
+}
+
+void RecordBatchFileWriter::close(libmexclass::proxy::method::Context&
context) {
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(writer->Close(), context,
+
error::IPC_RECORD_BATCH_WRITE_CLOSE_FAILED);
+}
+
+} // namespace arrow::matlab::io::ipc::proxy
\ No newline at end of file
diff --git
a/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.h
b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.h
new file mode 100644
index 0000000000..bfd83504f1
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.h
@@ -0,0 +1,42 @@
+// 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 "arrow/ipc/writer.h"
+#include "libmexclass/proxy/Proxy.h"
+
+namespace arrow::matlab::io::ipc::proxy {
+
+class RecordBatchFileWriter : public libmexclass::proxy::Proxy {
+ public:
+ RecordBatchFileWriter(std::shared_ptr<arrow::ipc::RecordBatchWriter> writer);
+
+ ~RecordBatchFileWriter() = default;
+
+ static libmexclass::proxy::MakeResult make(
+ const libmexclass::proxy::FunctionArguments& constructor_arguments);
+
+ protected:
+ std::shared_ptr<arrow::ipc::RecordBatchWriter> writer;
+
+ void writeRecordBatch(libmexclass::proxy::method::Context& context);
+
+ void writeTable(libmexclass::proxy::method::Context& context);
+
+ void close(libmexclass::proxy::method::Context& context);
+};
+
+} // namespace arrow::matlab::io::ipc::proxy
\ No newline at end of file
diff --git a/matlab/src/cpp/arrow/matlab/proxy/factory.cc
b/matlab/src/cpp/arrow/matlab/proxy/factory.cc
index 53a19da82e..8326b43719 100644
--- a/matlab/src/cpp/arrow/matlab/proxy/factory.cc
+++ b/matlab/src/cpp/arrow/matlab/proxy/factory.cc
@@ -34,6 +34,8 @@
#include "arrow/matlab/io/csv/proxy/table_writer.h"
#include "arrow/matlab/io/feather/proxy/reader.h"
#include "arrow/matlab/io/feather/proxy/writer.h"
+#include "arrow/matlab/io/ipc/proxy/record_batch_file_reader.h"
+#include "arrow/matlab/io/ipc/proxy/record_batch_file_writer.h"
#include "arrow/matlab/tabular/proxy/record_batch.h"
#include "arrow/matlab/tabular/proxy/schema.h"
#include "arrow/matlab/tabular/proxy/table.h"
@@ -107,6 +109,8 @@ libmexclass::proxy::MakeResult Factory::make_proxy(
REGISTER_PROXY(arrow.c.proxy.ArrayImporter ,
arrow::matlab::c::proxy::ArrayImporter);
REGISTER_PROXY(arrow.c.proxy.Schema ,
arrow::matlab::c::proxy::Schema);
REGISTER_PROXY(arrow.c.proxy.RecordBatchImporter ,
arrow::matlab::c::proxy::RecordBatchImporter);
+ REGISTER_PROXY(arrow.io.ipc.proxy.RecordBatchFileReader ,
arrow::matlab::io::ipc::proxy::RecordBatchFileReader);
+ REGISTER_PROXY(arrow.io.ipc.proxy.RecordBatchFileWriter ,
arrow::matlab::io::ipc::proxy::RecordBatchFileWriter);
// clang-format on
return libmexclass::error::Error{error::UNKNOWN_PROXY_ERROR_ID,
diff --git a/matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileReader.m
b/matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileReader.m
new file mode 100644
index 0000000000..fc15863603
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileReader.m
@@ -0,0 +1,64 @@
+%RECORDBATCHFILEREADER Class for reading Arrow RecordBatches from the
+% Arrow binary (IPC) format.
+
+% 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.
+
+classdef RecordBatchFileReader < matlab.mixin.Scalar
+
+ properties(SetAccess=private, GetAccess=public, Hidden)
+ Proxy
+ end
+
+ properties (Dependent, SetAccess=private, GetAccess=public)
+ NumRecordBatches
+ Schema
+ end
+
+ methods
+ function obj = RecordBatchFileReader(filename)
+ arguments
+ filename(1, 1) string {mustBeNonzeroLengthText}
+ end
+ args = struct(Filename=filename);
+ proxyName = "arrow.io.ipc.proxy.RecordBatchFileReader";
+ obj.Proxy = arrow.internal.proxy.create(proxyName, args);
+ end
+
+ function numRecordBatches = get.NumRecordBatches(obj)
+ numRecordBatches = obj.Proxy.getNumRecordBatches();
+ end
+
+ function schema = get.Schema(obj)
+ proxyID = obj.Proxy.getSchema();
+ proxyName = "arrow.tabular.proxy.Schema";
+ proxy = libmexclass.proxy.Proxy(ID=proxyID, Name=proxyName);
+ schema = arrow.tabular.Schema(proxy);
+ end
+
+ function rb = read(obj, index)
+ arguments
+ obj(1, 1) arrow.io.ipc.RecordBatchFileReader
+ index(1, 1)
+ end
+ index = arrow.internal.validate.index.numeric(index, "int32");
+ args = struct(Index=index);
+ proxyID = obj.Proxy.readRecordBatchAtIndex(args);
+ proxyName = "arrow.tabular.proxy.RecordBatch";
+ proxy = libmexclass.proxy.Proxy(ID=proxyID, Name=proxyName);
+ rb = arrow.tabular.RecordBatch(proxy);
+ end
+ end
+end
\ No newline at end of file
diff --git a/matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileWriter.m
b/matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileWriter.m
new file mode 100644
index 0000000000..aee4acf5c1
--- /dev/null
+++ b/matlab/src/matlab/+arrow/+io/+ipc/RecordBatchFileWriter.m
@@ -0,0 +1,77 @@
+%RECORDBATCHFILEWRITER Class for serializing record batches to a file using
+% the IPC format.
+
+% 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.
+
+classdef RecordBatchFileWriter < matlab.mixin.Scalar
+
+ properties(SetAccess=private, GetAccess=public, Hidden)
+ Proxy
+ end
+
+ methods
+ function obj = RecordBatchFileWriter(filename, schema)
+ arguments
+ filename(1, 1) string {mustBeNonzeroLengthText}
+ schema(1, 1) arrow.tabular.Schema
+ end
+ args = struct(Filename=filename, SchemaProxyID=schema.Proxy.ID);
+ proxyName = "arrow.io.ipc.proxy.RecordBatchFileWriter";
+ obj.Proxy = arrow.internal.proxy.create(proxyName, args);
+ end
+
+ function writeRecordBatch(obj, recordBatch)
+ arguments
+ obj(1, 1) arrow.io.ipc.RecordBatchFileWriter
+ recordBatch(1, 1) arrow.tabular.RecordBatch
+ end
+
+ args = struct(RecordBatchProxyID=recordBatch.Proxy.ID);
+ obj.Proxy.writeRecordBatch(args);
+ end
+
+ function writeTable(obj, arrowTable)
+ arguments
+ obj(1, 1) arrow.io.ipc.RecordBatchFileWriter
+ arrowTable(1, 1) arrow.tabular.Table
+ end
+
+ args = struct(TableProxyID=arrowTable.Proxy.ID);
+ obj.Proxy.writeTable(args);
+ end
+
+ function write(obj, tabularObj)
+ arguments
+ obj(1, 1) arrow.io.ipc.RecordBatchFileWriter
+ tabularObj(1, 1)
+ end
+ if isa(tabularObj, "arrow.tabular.RecordBatch")
+ obj.writeRecordBatch(tabularObj);
+ elseif isa(tabularObj, "arrow.tabular.Table")
+ obj.writeTable(tabularObj);
+ else
+ id = "arrow:matlab:ipc:write:InvalidType";
+ msg = "tabularObj input argument must be an instance of " + ...
+ "either arrow.tabular.RecordBatch or arrow.tabular.Table.";
+ error(id, msg);
+ end
+ end
+
+ function close(obj)
+ obj.Proxy.close();
+ end
+ end
+end
diff --git a/matlab/test/arrow/io/ipc/tRecordBatchFileReader.m
b/matlab/test/arrow/io/ipc/tRecordBatchFileReader.m
new file mode 100644
index 0000000000..eb0069d307
--- /dev/null
+++ b/matlab/test/arrow/io/ipc/tRecordBatchFileReader.m
@@ -0,0 +1,184 @@
+%TRECORDBATCHFILEREADER Unit tests for arrow.io.ipc.RecordBatchFileReader.
+
+% 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.
+classdef tRecordBatchFileReader < matlab.unittest.TestCase
+
+ properties
+ DataFolder
+ ZeroBatchFile
+ OneBatchFile
+ MultipleBatchFile
+ end
+
+ methods(TestClassSetup)
+ function setupDataFolder(testCase)
+ import matlab.unittest.fixtures.TemporaryFolderFixture
+ fixture = testCase.applyFixture(TemporaryFolderFixture);
+ testCase.DataFolder = string(fixture.Folder);
+ end
+
+ function setupZeroBatchFile(testCase)
+ fieldA = arrow.field("A", arrow.string());
+ fieldB = arrow.field("B", arrow.float32());
+ schema = arrow.schema([fieldA, fieldB]);
+ fname = fullfile(testCase.DataFolder, "ZeroBatchFile.arrow");
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ writer.close();
+ testCase.ZeroBatchFile = fname;
+ end
+
+ function setupOneBatchFile(testCase)
+ t = table(["Row1"; "Row2"], single([1; 2]), VariableNames=["A",
"B"]);
+ recordBatch = arrow.recordBatch(t);
+ fname = fullfile(testCase.DataFolder, "OneBatchFile.arrow");
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname,
recordBatch.Schema);
+ writer.writeRecordBatch(recordBatch);
+ writer.close();
+ testCase.OneBatchFile = fname;
+ end
+
+ function setupMultipleBatchFile(testCase)
+ t1 = table(["Row1"; "Row2"], single([1; 2]), VariableNames=["A",
"B"]);
+ t2 = table(["Row3"; "Row4"], single([3; 4]), VariableNames=["A",
"B"]);
+ recordBatch1 = arrow.recordBatch(t1);
+ recordBatch2 = arrow.recordBatch(t2);
+ fname = fullfile(testCase.DataFolder, "MultipleBatchFile.arrow");
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname,
recordBatch1.Schema);
+ writer.writeRecordBatch(recordBatch1);
+ writer.writeRecordBatch(recordBatch2);
+ writer.close();
+ testCase.MultipleBatchFile = fname;
+ end
+ end
+
+ methods (Test)
+ function ZeroLengthFilenameError(testCase)
+ % Verify RecordBatchFileReader throws an exception with the
+ % identifier MATLAB:validators:mustBeNonzeroLengthText if the
+ % filename input argument given is a zero length string.
+ fcn = @() arrow.io.ipc.RecordBatchFileReader("");
+ testCase.verifyError(fcn,
"MATLAB:validators:mustBeNonzeroLengthText");
+ end
+
+ function MissingStringFilenameError(testCase)
+ % Verify RecordBatchFileReader throws an exception with the
+ % identifier MATLAB:validators:mustBeNonzeroLengthText if the
+ % filename input argument given is a missing string.
+ fcn = @() arrow.io.ipc.RecordBatchFileReader(string(missing));
+ testCase.verifyError(fcn,
"MATLAB:validators:mustBeNonzeroLengthText");
+ end
+
+ function FilenameInvalidTypeError(testCase)
+ % Verify RecordBatchFileReader throws an exception with the
+ % identifier MATLAB:validators:UnableToConvert if the filename
+ % input argument is neither a scalar string nor a char vector.
+ fcn = @() arrow.io.ipc.RecordBatchFileReader(table);
+ testCase.verifyError(fcn, "MATLAB:validation:UnableToConvert");
+ end
+
+ function NumRecordBatches(testCase)
+ % Verify the getter method for NumRecordBatches returns the
+ % expected value.
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.ZeroBatchFile);
+ testCase.verifyEqual(reader.NumRecordBatches, int32(0));
+
+ reader = arrow.io.ipc.RecordBatchFileReader(testCase.OneBatchFile);
+ testCase.verifyEqual(reader.NumRecordBatches, int32(1));
+
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.MultipleBatchFile);
+ testCase.verifyEqual(reader.NumRecordBatches, int32(2));
+ end
+
+ function NumRecordNoSetter(testCase)
+ % Verify the NumRecordBatches property is not settable.
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.ZeroBatchFile);
+ testCase.verifyError(@() setfield(reader, "NumRecordBatches",
int32(10)), "MATLAB:class:SetProhibited");
+ end
+
+ function Schema(testCase)
+ % Verify the getter method for Schema returns the
+ % expected value.
+ fieldA = arrow.field("A", arrow.string());
+ fieldB = arrow.field("B", arrow.float32());
+ expectedSchema = arrow.schema([fieldA fieldB]);
+
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.ZeroBatchFile);
+ testCase.verifyEqual(reader.Schema, expectedSchema);
+
+ reader = arrow.io.ipc.RecordBatchFileReader(testCase.OneBatchFile);
+ testCase.verifyEqual(reader.Schema, expectedSchema);
+
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.MultipleBatchFile);
+ testCase.verifyEqual(reader.Schema, expectedSchema);
+ end
+
+ function SchemaNoSetter(testCase)
+ % Verify the Schema property is not settable.
+ fieldC = arrow.field("C", arrow.date32());
+ schema = arrow.schema(fieldC);
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.ZeroBatchFile);
+ testCase.verifyError(@() setfield(reader, "Schema", schema),
"MATLAB:class:SetProhibited");
+ end
+
+ function readInvalidIndexType(testCase)
+ % Verify read throws an exception with the identifier
+ % arrow:badsubscript:NonNumeric if the index argument given is
+ % not numeric.
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.MultipleBatchFile);
+
+ fcn = @() reader.read("index");
+ testCase.verifyError(fcn, "arrow:badsubscript:NonNumeric");
+ end
+
+ function readInvalidNumericIndex(testCase)
+ % Verify read throws an exception if the index argument given
+ % is nonpositive or noninteger number.
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.MultipleBatchFile);
+ fcn = @() reader.read(-1);
+ testCase.verifyError(fcn, "arrow:badsubscript:NonPositive");
+ fcn = @() reader.read(0);
+ testCase.verifyError(fcn, "arrow:badsubscript:NonPositive");
+ fcn = @() reader.read(1.1);
+ testCase.verifyError(fcn, "arrow:badsubscript:NonInteger");
+ end
+
+ function readInvalidNumericIndexValue(testCase)
+ % Verify read throws an exception with the identifier
+ % arrow:io:ipc:InvalidIndex if the index given is greater
+ % than the NumRecordBatches in the file.
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.MultipleBatchFile);
+ fcn = @() reader.read(3);
+ testCase.verifyError(fcn, "arrow:io:ipc:InvalidIndex");
+ end
+
+ function readAtIndex(testCase)
+ % Verify read returns the expected RecordBatch for the given
+ % index.
+ t1 = table(["Row1"; "Row2"], single([1; 2]), VariableNames=["A",
"B"]);
+ t2 = table(["Row3"; "Row4"], single([3; 4]), VariableNames=["A",
"B"]);
+
+ reader =
arrow.io.ipc.RecordBatchFileReader(testCase.MultipleBatchFile);
+
+ actual1 = reader.read(1);
+ expected1 = arrow.recordBatch(t1);
+ testCase.verifyEqual(actual1, expected1);
+
+ actual2 = reader.read(2);
+ expected2 = arrow.recordBatch(t2);
+ testCase.verifyEqual(actual2, expected2);
+ end
+ end
+end
\ No newline at end of file
diff --git a/matlab/test/arrow/io/ipc/tRecordBatchFileWriter.m
b/matlab/test/arrow/io/ipc/tRecordBatchFileWriter.m
new file mode 100644
index 0000000000..25bbf4474e
--- /dev/null
+++ b/matlab/test/arrow/io/ipc/tRecordBatchFileWriter.m
@@ -0,0 +1,211 @@
+%TRECORDBATCHFILEWRITER Unit tests for arrow.io.ipc.RecordBatchFileWriter.
+
+% 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.
+
+classdef tRecordBatchFileWriter < matlab.unittest.TestCase
+
+ methods
+ function folder = setupTemporaryFolder(testCase)
+ import matlab.unittest.fixtures.TemporaryFolderFixture
+ fixture = testCase.applyFixture(TemporaryFolderFixture);
+ folder = string(fixture.Folder);
+ end
+ end
+
+ methods (Test)
+ function ZeroLengthFilenameError(testCase)
+ % Verify RecordBatchFileWriter throws an exception with the
+ % identifier MATLAB:validators:mustBeNonzeroLengthText if the
+ % filename input argument given is a zero length string.
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ fcn = @() arrow.io.ipc.RecordBatchFileWriter("", schema);
+ testCase.verifyError(fcn,
"MATLAB:validators:mustBeNonzeroLengthText");
+ end
+
+ function MissingStringFilenameError(testCase)
+ % Verify RecordBatchFileWriter throws an exception with the
+ % identifier MATLAB:validators:mustBeNonzeroLengthText if the
+ % filename input argument given is a missing string.
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ fcn = @() arrow.io.ipc.RecordBatchFileWriter(string(missing),
schema);
+ testCase.verifyError(fcn,
"MATLAB:validators:mustBeNonzeroLengthText");
+ end
+
+ function FilenameInvalidTypeError(testCase)
+ % Verify RecordBatchFileWriter throws an exception with the
+ % identifier MATLAB:validators:UnableToConvert if the filename
+ % input argument is neither a scalar string nor a char vector.
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ fcn = @() arrow.io.ipc.RecordBatchFileWriter(table, schema);
+ testCase.verifyError(fcn, "MATLAB:validation:UnableToConvert");
+ end
+
+ function InvalidSchemaType(testCase)
+ % Verify RecordBatchFileWriter throws an exception with the
+ % identifier MATLAB:validators:UnableToConvert if the schema
+ % input argument is not an arrow.tabular.Schema instance.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.field("A", arrow.float64());
+ fcn = @() arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ testCase.verifyError(fcn, "MATLAB:validation:UnableToConvert");
+ end
+
+ function writeRecordBatchInvalidType(testCase)
+ % Verify writeRecordBatch throws an exception with the
+ % identifier MATLAB:validators:UnableToConvert if the
+ % recordBatch input argument given is not an
+ % arrow.tabular.RecordBatch instance.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ arrowTable = arrow.table(table([1 2 3 4]', VariableNames="A"));
+ fcn = @() writer.writeRecordBatch(arrowTable);
+ testCase.verifyError(fcn, "MATLAB:validation:UnableToConvert");
+ end
+
+ function writeTableInvalidType(testCase)
+ % Verify writeTable throws an exception with the
+ % identifier MATLAB:validators:UnableToConvert if the table
+ % input argument given is not an arrow.tabular.Table instance.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ arrowRecordBatch = arrow.recordBatch(table([1 2 3 4]',
VariableNames="A"));
+ fcn = @() writer.writeTable(arrowRecordBatch);
+ testCase.verifyError(fcn, "MATLAB:validation:UnableToConvert");
+ end
+
+ function writeInvalidType(testCase)
+ % Verify writeTable throws an exception with the
+ % identifier arrow:matlab:ipc:write:InvalidType if the
+ % tabularObj input argument given is neither an
+ % arrow.tabular.Table or an arrow.tabular.RecordBatch.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ fcn = @() writer.write(schema);
+ testCase.verifyError(fcn, "arrow:matlab:ipc:write:InvalidType");
+ end
+
+ function writeRecordBatchInvalidSchema(testCase)
+ % Verify writeRecordBatch throws an exception with the
+ % identifier arrow:io:ipc:FailedToWriteRecordBatch if the
+ % schema of the given record batch does match the expected
+ % schema.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+
+ arrowRecordBatch = arrow.recordBatch(table([1 2 3 4]',
VariableNames="B"));
+ fcn = @() writer.writeRecordBatch(arrowRecordBatch);
+ testCase.verifyError(fcn, "arrow:io:ipc:FailedToWriteRecordBatch");
+ end
+
+ function writeTableInvalidSchema(testCase)
+ % Verify writeTable throws an exception with the
+ % identifier arrow:io:ipc:FailedToWriteRecordBatch if the
+ % schema of the given table does match the expected schema.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+
+ arrowTable = arrow.table(table([1 2 3 4]', VariableNames="B"));
+ fcn = @() writer.writeTable(arrowTable);
+ testCase.verifyError(fcn, "arrow:io:ipc:FailedToWriteRecordBatch");
+ end
+
+ function writeInvalidSchema(testCase)
+ % Verify write throws an exception with the
+ % identifier arrow:io:ipc:FailedToWriteRecordBatch if the
+ % schema of the given record batch or table does match the
+ % expected schema.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+
+ arrowTable = arrow.table(table([1 2 3 4]', VariableNames="B"));
+ fcn = @() writer.write(arrowTable);
+ testCase.verifyError(fcn, "arrow:io:ipc:FailedToWriteRecordBatch");
+
+ arrowRecordBatch = arrow.recordBatch(table([1 2 3 4]',
VariableNames="B"));
+ fcn = @() writer.write(arrowRecordBatch);
+ testCase.verifyError(fcn, "arrow:io:ipc:FailedToWriteRecordBatch");
+ end
+
+ function writeRecordBatchSmoke(testCase)
+ % Verify writeRecordBatch does not error or issue a warning
+ % if it successfully writes the record batch to the file.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ arrowRecordBatch = arrow.recordBatch(table([1 2 3 4]',
VariableNames="A"));
+
+ fcn = @() writer.writeRecordBatch(arrowRecordBatch);
+ testCase.verifyWarningFree(fcn);
+ end
+
+ function writeTableBatchSmoke(testCase)
+ % Verify writeTable does not error or issue a warning
+ % if it successfully writes the table to the file.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ arrowTable = arrow.table(table([1 2 3 4]', VariableNames="A"));
+
+ fcn = @() writer.writeTable(arrowTable);
+ testCase.verifyWarningFree(fcn);
+ end
+
+ function writeSmoke(testCase)
+ % Verify write does not error or issue a warning if it
+ % successfully writes the record batch or table to the file.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ arrowRecordBatch = arrow.recordBatch(table([1 2 3 4]',
VariableNames="A"));
+
+ fcn = @() writer.write(arrowRecordBatch);
+ testCase.verifyWarningFree(fcn);
+
+ arrowTable = arrow.table(table([1 2 3 4]', VariableNames="A"));
+ fcn = @() writer.write(arrowTable);
+ testCase.verifyWarningFree(fcn);
+ end
+
+ function closeSmoke(testCase)
+ % Verify close does not error or issue a warning if it was
+ % successful.
+ folder = testCase.setupTemporaryFolder();
+ fname = fullfile(folder, "data.arrow");
+ schema = arrow.schema(arrow.field("A", arrow.float64()));
+ writer = arrow.io.ipc.RecordBatchFileWriter(fname, schema);
+ arrowTable = arrow.table(table([1 2 3 4]', VariableNames="A"));
+ writer.write(arrowTable);
+ fcn = @() writer.close();
+ testCase.verifyWarningFree(fcn);
+ end
+ end
+end
\ No newline at end of file
diff --git a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
index 0a747e648c..5ed68ec246 100644
--- a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
+++ b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
@@ -79,7 +79,9 @@ set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_SOURCES
"${CMAKE_SOURCE_DIR}/src/cpp/a
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/c/proxy/array.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/c/proxy/array_importer.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/c/proxy/schema.cc"
-
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/c/proxy/record_batch_importer.cc")
+
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/c/proxy/record_batch_importer.cc"
+
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_reader.cc"
+
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/io/ipc/proxy/record_batch_file_writer.cc")
set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_FACTORY_INCLUDE_DIR
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/proxy")