罗兰谈MATLAB的艺术

将想法转化为MATLAB

请注意

罗兰谈MATLAB的艺术已存档,不会更新。

使用memmapfile浏览“大数据”二进制文件

本周,来自MATLAB产品管理的Ken Atwell将讨论如何使用memmapfile作为一种浏览“大数据”二进制文件的方式。

memmapfile(对于“内存映射文件”)用于访问二进制文件,而不需要求助于低级文件I/O函数,如从文件中读.它包括声明二进制数据结构的能力,可以自由混合数据类型和大小。最初是为了方便阅读记录列表,memmapfile在大数据中也有应用。今天的文章将研究大二进制文件的按列访问,以及如何在二进制文件开头的元数据中导航。

内容

实验参数

首先,创建一个存储在磁盘上的可能很大的2D矩阵。numRows而且numColumns可换不同尺寸进行实验。为了保持简单和快速,矩阵的大小小于1gb。这很难说是“大数据”,你可以调整这里的参数来制造一个更大的问题。当然,请注意,运行此代码所需的磁盘空间将随着您创建的矩阵大小而增加。

scratchFolder = tempdir;numRows = 1e5;numColumns = 1e3;

创建测试文件

创建草稿文件。根据上面声明的大小,这可能需要几分钟到几分钟的时间来运行。因为类型的数据正在创建,文件将消耗8 * numRows * numColumns可用磁盘空间字节数。

的价值(r、c)在矩阵中设为c * 1000000 + r.这将使我们很容易查看输出,并认识到我们正在获得所期望的值。

文件名= [mmf的int2str (numRows)“x”int2str (numColumns)“.dat”];filename = fullfile(scratchFolder, filename);F = fopen(文件名,' w ');colNum = 1:numColumns column = (1:numRows)' + colNum*1000000;写入文件(f,列,“双”);结束文件关闭(f);

memmapfile适用于整个数据集

为了创建一个内存映射文件,我们调用memmapfile通过这两个论证:

  1. 包含数据的文件名
  2. “格式”,它是一个单元格数组,有三个组成部分:a.数据类型(在这个例子中),b.数据的大小(大小矩阵)numRows通过numColumns在本例中),c.分配给该数据的名称(对于本例中的“matrix”)

这是的基本用法memmapfile,它将整个数据集封装在一次访问中。当处理“大数据”时,你会希望避免这样的单一访问。如果数据的大小足够大,你的电脑可能会变得没有反应(“),因为它忙于创建交换空间,以努力读取整个矩阵。的如果声明是为了防止你不小心这么做。如果您正在试验的数据大小大于计算机中可用的物理内存,则需要跳过此步骤。

防止创建内存破坏矩阵。如果numRows*numColumns*8 > 1e9错误(“尺寸可能太大了;你确定要这么做吗?”结束Mm = memmapfile(文件名,“格式”, {“双”, [numRows numColumns],“米”});m = mm. datam;% #好< NASGU >

无论如何,明确释放所使用的内存。

清楚(“米”);

memmapfile按列访问

这里有一个更聪明的方法来访问大数据,一次一列。而不是创建一个单一的变量numRows * numColumns大的,我们创建一个numRows * 1向量,是重复的numColumnsTimes(注意此代码现在使用的是可选的“重复”参数memmapfile).这个细微的差别允许大矩阵一次只读取一列,大概是在可用内存中。变量被命名为乔丹表示数据的第j列。

Mm = memmapfile(文件名,“格式”, {“双”, [numRows 1],“乔丹”},...“重复”, numColumns);

代码抽查第17列。

如果~ isequal (mm.Data(17)。乔丹,(1:numRows)' + 17*1000000) error(“数据没有正确读取回来!”);结束

memmapfile允许创造性地使用“Repeat”,如果你的应用程序需要它。例如,您可以读取半列的块,而不是整个列的向量:

memmapfile(文件名,“格式”, {“双”, [numRows/2 1],“乔丹”},“重复”, numColumns * 2);

或包含多列的块:

memmapfile(文件名,“格式”, {“双”, [numRows*10 1],“乔丹”},“重复”, numColumns / 10);

当然,首先要确保数据的大小能被这些倍数均匀整除,否则将创建一个memmapfile这并不能准确地反映它所基于的实际文件。

关于内存映射文件和虚拟内存的说明:如果您的应用程序循环遍历许多内存映射数据列,您可能会发现Windows任务管理器或者是OS X活动监视器将开始攀登。这可能有点误导人。而memmapfile将消耗部分计算机的虚拟内存空间(只有在您仍然使用32位版本的MATLAB时才会产生实际后果),物理内存(RAM)将不会被使用。的分配上面的操作有可能失败,只是因为该操作正在拉出整个的内容memmapfile转换为一个工作区变量,以及工作区变量(包括)驻留在RAM中。关于虚拟内存的全面讨论超出了本文的范围;的维基百科上关于虚拟内存的文章是一个起点,如果你想了解更多。

带有XML头的数据文件

上面的代码假设矩阵出现在数据文件的最开始。然而,许多数据文件以某种形式的元数据开始,然后是“有效载荷”,即数据本身。

对于这个博客,将创建一个包含一些元数据和“真实”数据的文件。元数据使用xml样式的格式表示。这种特殊的格式是为本文创建的,但它代表了实际的元数据。通常,元数据指示实际数据开始的文件的偏移量,该偏移量在headerLength属性在标题的第一行中。接下来是一个var声明文件中包含的变量的名称、类型和大小。该文件将只包含一个变量,但从概念上讲,该文件可以包含多个变量。

strNumC = int2str(numColumns);strNumR = int2str(numRows);标题= [...' < datFile headerLength = 00000000 > 'char (10)...' ”、“strNumC’”/ > 'char (10)...' < / datFile >”char (10)...];插入头长度%头= strrep(头,“00000000”sprintf (' % 08.0 f '、长度(头)));disp(头)
   .
文件名= [mmf的int2str (numRows)“x”int2str (numColumns)“_header.dat”];filename = fullfile(scratchFolder, filename);F = fopen(文件名,' w ');写入文件(f,头,“字符”);colNum = 1:numColumns column = (1:numRows)' + colNum*1000000;写入文件(f,列,“双”);结束文件关闭(f);

读取XML报头

现在头文件将被读入并解析。而xlmread可以用来让DOM节点遍历XML数据结构,正则表达式通常可以作为从XML中获取信息的一种快速而不实用的方法。如果你不熟悉正则表达式,这个例子只需要理解:

  • (\ d +)提取一个数字字符串
  • (\ w +)提取一个单词(字母数字字符串)
  • \ s +跳过空白

读取文件的第一行以确定标题的长度(由正则表达式提取),然后使用该信息读取完整的标题。最后,使用第二个更复杂的正则表达式来提取标题后面的二进制数据“blob”中包含的变量的名称、类型和大小信息。

F = fopen(文件名,“r”);firstLine = fgetl(f);文件关闭(f);得力% #好< NOPTS >
firstLine =  .使用实例
获取长度并将字符串转换为double类型headerLength = regexp(firstLine,“headerLength = (\ d +)”“令牌”);headerLength = (str2double(头长度{1}{1}))% #好吧
headerLength = 95
F = fopen(文件名,“r”);header = fread(f, headerLength,“字符= >字符”)”;文件关闭(f);扫描元数据的类型、大小和名称Vars = regexp(头,的名字= " (\ w +) " \ s + type = " (\ w +) " \ s +大小= " (\ d +) (\ d +)“‘...“令牌”);

创建内存映射文件

最后,创建一个memmapfile对于变量。返回的单元格数组正则表达式的预期输入参数匹配的新单元格数组memmapfile函数。

将XML中的数据重新组织成memmapfile所期望的形式mmfFormater = {...“格式”...{var {1} {2},...[str2double (var {1} {3}), 1],...var {1} {1}}...“重复”str2double (var {1} {4})};Mm = memmapfile(文件名,“抵消”, headerLength, mmfFormater{:});mj = mm.Data(17).mj;检查第17列如果~isequal(mj, (1:numRows)' + 17*1000000) error(“矩阵‘mj’没读对!”);结束

结论

我希望这篇博客对那些努力将大块二进制数据导入MATLAB的读者有用。虽然这篇文章没有涉及,memmapfile也可以用来加载行主数据,和二维“瓷砖”的数据。

当你完成实验时,记得删除你已经创建的临时文件。

你用过memmapfile或者其他从大型二进制文件增量读取的技术?分享你的小贴士在这里




MATLAB®R2013a发布


评论

如欲留言,请点击在这里登录您的MathWorks帐户或创建一个新帐户。

Baidu
map