如何将文件中的数据导入变量数组? (Matlab)

How to import data from file into variable arrays? (Matlab)

我使用 matlab 创建了 .txt 文件,这些文件有不同的 3 列,由制表符(字符串、浮点、浮点)和不同的行数分隔。

我正在尝试将这 3 列数据中的每一列读入 3 个不同的变量。这是我的代码:

fileId = fopen('file.txt');

% Storing columns from txt file into appropriate compartment data arrays
compartment_name = textscan(fileId,'%s%*f%*f','Delimiter','\t'); % column of strings
compartment_length = textscan(fileId,'%*s%f%*f','Delimiter','\t'); % column of doubles
compartment_diameter = textscan(fileId,'%*s%*f%f','Delimiter','\t'); % column of doubles

fclose('file.txt');

我收到 compartment_name 的正确数据(1x1 单元格包含 106x1 单元格(每个单元格都是一个字符串)),但是 compartment_lengthcompartment_diameter return 包含 0x1 双倍的空 1x1 单元格。

有什么想法吗?

还有 - 有什么简单的方法可以将 1x1 单元格转换为数组吗?即对于 compartment_name,它将是一个 1x106 字符串数组 ?

正如@jgrant 指出的那样,问题是如果您想重新读取文件的某些部分,您必须将文件位置指示器重置为文件的开头。

我真的不明白你为什么要尝试调用 textscan 三次,textscan 的输出是一个单元格的原因正是你可以调用一次它,然后分隔输出列:

tmpcell = textscan(fileId,'%s%f%f','Delimiter','\t'); % column of strings

compartment_name = tmpcell{1};
compartment_length = tmpcell{2};
compartment_diameter = tmpcell{3};

% or if you want to be fancy about it:
%[compartment_name, compartment_length, compartment_diameter] = tmpcell{:};

我写这个答案的原因是你的最后注释:

Also - is there any easy way for me to convert the 1x1 cells into an array? ie for compartment_name, it would be an array of 1x106 strings ?

这暗示您对 MATLAB 中的字符串感到困惑。在 MATLAB 中,字符串本质上是 整数数组 。您可以通过对字符串执行任何类型的算术运算来亲眼看到这一点:

>> tmpstring = 'asdf'

tmpstring =

asdf

>> tmpstring*1

ans =

    97   115   100   102

您看到的数字是字符串中字符的 ASCII 表示形式。这也适用于其他方式:您可以通过将整数放入数组来构建字符串。事实上,就所有意图和目的而言,字符串 整数数组:

>> isequal([97   115   100   102],'asdf')

ans =

     1

这也暗示了 MATLAB 中字符串的一些限制。你的问题是你不能简单地创建一个字符串数组。那就是字符串连接:如果 string1string2 都只是整数数组,那么 [string1, string2] 就是两个字符串的连接。

然后您可以考虑使用 [string1; string2] 水平堆叠字符串。现在,这与它对两个整数数组的作用完全一样:如果字符串的长度相等(我现在的长度是指size(string1,2)),你只能这样做。所以在一般情况下,您只能将字符串一起存储在一个非均匀容器中,即 MATLAB 中的单元格。拥有单元格后,您的元素可以具有任何类型和形状,因此您可以轻松地将任意长度的字符串推在一起,垂直或水平堆叠,但您喜欢它们。

所以考虑 textscan。您需要实现此函数,该函数将从文件中读取 return 数据。数据可以是数字或字符串。你做什么工作? textscan 正在做的事情:return 数字列作为数组(因为每一行都有一个标量数据),return 字符串作为单元格(因为每一行包含一个字符串,即向量在自身!)。您 可以 水平堆叠字符串,但这仅在给定列中的每一行包含相同数量的字符时才有效,这显然不应假设,也不应规定。您 可以 仍然将字符串填充到最长的元素和 return 堆叠字符数组,但这会在大多数实际应用程序中引入不必要的开销。 (旁注:textscan return 是一个单元格行向量作为其输出,每个单元格元素包含给定列中的完整数据。对于数字列,此 "full data" 是数组列向量,对于字符串列,它是一个单元格列向量。)

因此 textscan return 将其字符串列作为单元格是合理的。如果愿意,您自己仍然可以将字符串堆叠到二维字符串数组中,但在大多数情况下这并不实用。这真的取决于您的应用程序。

一个最小的例子:考虑 tmp.inp 包含

asf 3 4
asdg 2 3
asd 1 4

现在

>> fid=fopen('tmp.inp','r'); outcell=textscan(fid,'%s%f%f'), fclose(fid);

outcell = 

    {3x1 cell}    [3x1 double]    [3x1 double]

这表明 outcell 的输出是一个单元格行向量,每个元素对应于从文件中读入的列。第 2 列和第 3 列周围的方括号表示这些单元格元素(即 outcell{2}outcell{3},不要与 outcell(2)outcell(3) 混淆)是数值数组。但是,第一个元素是单元格列向量:

>> outcell{1}

ans = 

    'asf'
    'asdg'
    'asd'

输出在每行上都带有引号,这表明这些是单元格中包含的单独字符串,但您也可以从

中看出这一点
>> whos ans
  Name      Size            Bytes  Class    Attributes

  ans       3x1               356  cell               

现在,正如我所说,您可以决定将您的列堆叠在一起,您只需要在您的单元格上调用 char()

>> char(outcell{1})

ans =

asf 
asdg
asd 

>> whos ans
  Name      Size            Bytes  Class    Attributes

  ans       3x4                24  char               

注意自动输出中缺少引号,以及输出本身的 class/size。 3x4 大小是通过将所有行填充到最长字符串的大小(即 4)来实现的。因此,输出的第一行和第三行以 space 结尾(这就是我们的意思字符串得到 padded).

如果您不执行此填充,您可以简单地引用读入的字符串作为它们的单元格元素:

>> outcell{1}{3}

ans =

asd

或者,按照您最初的意愿存储变量:

>> compartment_name=outcell{1}

compartment_name = 

    'asf'
    'asdg'
    'asd'

>> compartment_name{3}

ans =

asd