12

鉴于以下代码尝试在当前 MATLAB 路径中创建 2 个文件夹:

%%
u_path1 = native2unicode([107, 97, 116, 111, 95, 111, 117, 116, 111, 117], 'UTF-8');  % 'kato_outou'
u_path2 = native2unicode([233 129 142, 230 184 161, 229 191 156, 231 173 148], 'UTF-8');  % '過渡応答'

mkdir(u_path1);
mkdir(u_path2);

第一次mkdir调用成功,第二次调用失败,并显示错误消息“文件名、目录名或卷标语法不正确”。但是,在“当前文件夹”GUI 面板中手动创建文件夹([右键单击]⇒新建文件夹⇒[粘贴名称])不会遇到问题。这种故障出现在大多数 MATLAB 的低级 I/O 函数(dirfopencopyfilemovefile)中,我想使用所有这些函数。

环境是:

  • Win7 企业版(32 位,NTFS)
  • MATLAB R2012a

因此文件系统支持路径中的 Unicode 字符,MATLAB 可以存储真正的 Unicode 字符串(而不是“伪造”它们)。

mkdir 官方文档{1}通过说明调用函数的正确语法是优雅地避免了这个问题:

mkdir('folderName')

这表明唯一官方支持的函数调用是使用字符串文字作为文件夹名称参数的调用,而不是字符串变量这也暗示了这种eval方式——我正在测试它是否在我写这篇文章时工作。

我想知道是否有办法绕过这些限制。我会对以下解决方案感兴趣:

  • 不要依赖未记录/不受支持的 MATLAB 内容;

  • 不涉及系统范围的更改(例如更改操作系统的区域信息);

  • 最终可能依赖于非本地 MATLAB 库,只要生成的句柄/对象可以转换为 MATLAB 本地对象并照此操作即可;

  • 最终可能依赖于对路径的操作,使它们可以被标准 MATLAB 函数使用,即使是 Windows 特定的(例如短名称路径)。

稍后编辑

我正在寻找的是以下函数的实现,它们将隐藏已经编写的代码中的原始代码:

function  listing = dir(folder);
function  [status,message,messageid] = mkdir(folder1,folder2);
function  [status,message,messageid] = movefile(source,destination,flag);
function  [status,message,messageid] = copyfile(source,destination,flag);
function  [fileID, message] = fopen(filename, permission, machineformat, encoding);
function  status = fclose(fileID);
function  [A, count] = fread(fileID, sizeA, precision, skip, machineformat);
function  count = fwrite(fileID, A, precision, skip, machineformat);
function  status = feof(fileID);
function  status = fseek(fileID, offset, origin);
function  [C,position] = textscan(fileID, varargin);  %'This one is going to be funny'

并非所有输出类型都需要与原始 MATLAB 函数互换,但需要在函数调用之间保持一致(例如fileIDbetween fopenand fclose)。我将在获取/写入后立即使用实现更新此声明列表。


{1}用于“优雅”一词的非常宽松的含义。

4

2 回答 2

3

一些关于 MATLAB 如何处理文件名(和一般字符)的有用信息可以在这篇 UndocumentedMatlab 帖子的评论中找到(尤其是在 MathWorks 工作的 Steve Eddins 的评论)。简而言之:

MathWorks 开始将 MATLAB 代码库中的所有字符串处理转换为 UTF-16 .... 我们已经逐步接近它

——史蒂夫·埃丁斯,2014 年 12 月。

此声明暗示 MATLAB 版本越新,支持 UTF-16 的功能就越多。这反过来意味着,如果存在更新您的 MATLAB 版本的可能性,它可能是解决您的问题的简单方法。

根据问题中要求的功能,以下是用户在不同平台上测试的功能列表:

  • 以下命令在 MATLAB 中创建一个名称中包含 UTF16 字符的目录(在本示例中为希伯来语中的“תיקיה”):

    java.io.File(fullfile(pwd,native2unicode(...
              [255 254 234 5 217 5 231 5 217 5 212 5],'UTF-16'))).mkdir();
    

    测试:

  • 以下命令似乎也成功创建了目录:

    mkdir(native2unicode([255 254 234 5 217 5 231 5 217 5 212 5],'utf-16'));
    mkdir(native2unicode([215,170,215,153,215,167,215,153,215,148],'utf-8'));
    

    测试:

    • Windows 10 与 MATLAB R2015a 具有feature('DefaultCharacterSet')=>windows-1255Dev-iL
    • OSX Yosemite (10.10.4) 和 MATLAB R2014b by Matt
      的值在feature('DefaultCharacterSet')这里没有影响,因为编码是在命令中明确定义的native2unicode
  • 以下命令成功打开名称和内容均包含 unicode 字符的文件:

    fid = fopen([native2unicode([255,254,231,5,213,5,209,5,229,5],'utf-16') '.txt']);
    txt =  textscan(fid,'%s');
    

    测试:

    • Windows 10 与 MATLAB R2015a 具有feature('DefaultCharacterSet')=>windows-1255Dev-iL。注意:扫描的文本正确显示在变量视图中。可以从 MATLAB 编辑器中编辑和保存文本文件,并保持 UTF 字符不变。
    • OSX Yosemite (10.10.4) with MATLAB R2014b by Matt
      如果在使用之前feature('DefaultCharacterSet')设置为,则输出正确显示。这同样适用于变量视图。utf-8textscancelldisp(txt)
于 2015-08-09T16:42:13.013 回答
0

如果您在 Windows 上,请尝试使用 UTF-16,因为 NTFS 使用 UTF-16 进行文件名编码,并且 Windows 有两组 API:使用所谓的“Windows 代码页”(1250、1251、1252 等)并使用C 的char数据类型和使用wchar_t. 后一种类型在 Windows 上的大小为 2 个字节,足以存储 UTF-16 代码单元。

您第一次调用的原因是因为 Unicode 标准中的前 128 个代码点以 UTF-8 编码,与 128 个 ASCII 字符相同(这是为了向后兼容而专门制作的)。UTF-8 使用 1 字节代码单元(而不是 UTF-16 的 2 字节代码单元),并且通常诸如 MATLAB 之类的软件不处理文件名,因此它们只需要存储字节序列并将它们传递给 OS API。第二次调用失败,因为表示代码点的 UTF-8 字节序列可能被 Windows 过滤掉了,因为文件名中禁止了某些字节值。在符合 POSIX 的操作系统上,大多数 API 都是面向字节的,标准几乎阻止您在 API 中使用现有的多字节编码(例如,UTF-16、UTF-32),您必须使用char*具有 1 字节代码单元的 API 和编码:

POSIX.1-2008 仅对可移植字符集中字符的编码值提出以下要求:

...

  • 与实现相关的编码值和在实现支持的所有语言环境中应保持不变。
  • 与可移植字符集成员相关联的编码值均以单个字节表示。此外,如果该值存储在 C 语言类型 char 的对象中,则保证为正数(NUL 除外,它始终为零)。

并非所有符合 POSIX 的操作系统都会验证除句点或斜杠以外的文件名,因此您几乎可以在文件名中存储垃圾。Mac OS X 作为 POSIX 系统,使用面向字节的 ( char*) API,但底层 HFS+在NFD (规范化形式 D)中使用UTF-16 ,因此在保存文件名之前在 OS 级别完成了一些处理。

Windows 不执行任何类型的 Unicode 规范化,并以 UTF-16(假设使用 NTFS)或 Windows 代码页(不确定它们如何在文件系统级别处理这个 - 可能通过转换)中传递的任何形式存储文件名。

那么,这与 MATLAB 有何关系?好吧,它是跨平台的,因此必须处理许多问题。其中之一是 Windows 具有char用于 Windows 代码页的 API 和文件名中的某些禁止字符,而其他操作系统则没有。他们可以实现与系统相关的检查,但这将更难测试和支持(我猜很多代码搅动)。

我最好的建议是在 Windows 上使用 UTF-16,实现与平台相关的检查,或者如果需要可移植性则使用 ASCII。

于 2015-08-04T21:41:45.660 回答