如何在MATLAB中获取特定目录下的所有文件?

102

我需要获取 D:\dic 下的所有文件,并循环逐个进行进一步处理。

MATLAB支持这种操作吗?

其他脚本语言如PHP、Python中可以实现。

8个回答

129

更新: 鉴于这篇文章相当古老,而且我在此期间已经为自己的使用修改了这个实用程序很多次,所以我认为我应该发布一个新版本。我的最新代码可以在The MathWorks File Exchange上找到:dirPlus.m。你也可以从GitHub获取源代码。

我进行了许多改进。现在它提供了许多选项,可选择是否前缀完整路径或仅返回文件名(合并自DoresoomOz Radiano),并对文件名应用正则表达式模式(合并自Peter D)。此外,我还添加了对每个文件应用验证函数的功能,使您可以根据除了文件名之外的其他标准(例如文件大小、内容、创建日期等)来选择它们。


注意: 在 MATLAB 的更新版本(R2016b及更高版本)中,dir函数具有递归搜索功能!因此,您可以执行以下操作,以获取当前文件夹的所有子文件夹中所有*.m文件的列表:

dirData = dir('**/*.m');

旧代码:(仅记录)

以下是一个函数,它递归地搜索给定目录的所有子目录,收集它找到的所有文件名的列表:

function fileList = getAllFiles(dirName)

  dirData = dir(dirName);      %# Get the data for the current directory
  dirIndex = [dirData.isdir];  %# Find the index for directories
  fileList = {dirData(~dirIndex).name}';  %'# Get a list of the files
  if ~isempty(fileList)
    fileList = cellfun(@(x) fullfile(dirName,x),...  %# Prepend path to files
                       fileList,'UniformOutput',false);
  end
  subDirs = {dirData(dirIndex).name};  %# Get a list of the subdirectories
  validIndex = ~ismember(subDirs,{'.','..'});  %# Find index of subdirectories
                                               %#   that are not '.' or '..'
  for iDir = find(validIndex)                  %# Loop over valid subdirectories
    nextDir = fullfile(dirName,subDirs{iDir});    %# Get the subdirectory path
    fileList = [fileList; getAllFiles(nextDir)];  %# Recursively call getAllFiles
  end

end

将上述函数保存在MATLAB路径的某个位置之后,您可以按以下方式调用它:

fileList = getAllFiles('D:\dic');

3
很棒的解决方案。我不知道是否必要,但如果您在第一个fileList定义和subDirs定义之间插入以下行:fileList = cellfun(@(x) strcat([dirName,''],x),fileList,'UniformOutput',0); 它将返回每个文件的完整路径和文件名。 - Doresoom
2
@Doresoom:好建议,不过我选择使用FULLFILE,因为它可以为您处理文件分隔符的选择(在UNIX和Windows上不同)。此外,您可以只使用fileList = strcat(dirName,filesep,fileList);而不是使用CELLFUN,但是这样可能会产生额外的不必要的文件分隔符,FULLFILE也可以为您处理。 - gnovice
2
@gnovice,@Doreseoom - 根据http://www.mathworks.com/access/helpdesk/help/techdoc/ref/dir.html的说明,'dir'返回的顺序取决于操作系统。如果例如您设置了DOS DIRCMD变量以更改顺序,我不确定会发生什么。Octave可以处理它(.和..仍然是第一位),但我没有MATLAB进行测试。 - mtrw
2
@gnovice:这超出了OP的问题范围,但我发现将正则表达式构建到函数中很有用。if ~isempty(fileList) fileList = cellfun(@(x) fullfile(dirName,x),... %# Prepend path to files fileList,'UniformOutput',false); matchstart = regexp(fileList, pattern); fileList = fileList(~cellfun(@isempty, matchstart)); end并将函数签名更改为 getAllFiles(dirName, pattern)(也在倒数第二行)。 - Peter D
1
非常棒的答案,感谢!我已经完善了代码以支持两个额外参数 - https://dev59.com/C3E85IYBdhLWcg3wr1yx#26449095 - Oz Radiano
显示剩余9条评论

25
你需要使用 dir 函数来获取目录内容。
要循环遍历结果,只需执行以下操作:
dirlist = dir('.');
for i = 1:length(dirlist)
    dirlist(i)
end

这应该为您提供以下格式的输出,例如:

name: 'my_file'
date: '01-Jan-2010 12:00:00'
bytes: 56
isdir: 0
datenum: []

你能让它递归搜索包括子目录中的文件但排除目录本身吗? - Gtker
我脑海中没有,因为我不再经常使用Matlab,但这可能会对您有所帮助:http://www.mathworks.com/matlabcentral/fileexchange/19550-recursive-directory-listing - James B
2
如何排除 ... - Gtker
5
要排除 "." 和 "..",请从 "dir" 命令的输出中删除前两个条目。或者,如果你在寻找特定类型的文件,可以运行 dir('*.ext') 命令,它会自动排除目录(除非它们以 .ext 结尾)。 - Jonas

14

我使用了在这个好答案中提到的代码,并进行了扩展,以支持我需要的两个附加参数。这些参数是要过滤的文件扩展名和指示是否将完整路径连接到文件名的标志。

我希望它已经足够清楚,并且有人会发现它对他们有益。

function fileList = getAllFiles(dirName, fileExtension, appendFullPath)

  dirData = dir([dirName '/' fileExtension]);      %# Get the data for the current directory
  dirWithSubFolders = dir(dirName);
  dirIndex = [dirWithSubFolders.isdir];  %# Find the index for directories
  fileList = {dirData.name}';  %'# Get a list of the files
  if ~isempty(fileList)
    if appendFullPath
      fileList = cellfun(@(x) fullfile(dirName,x),...  %# Prepend path to files
                       fileList,'UniformOutput',false);
    end
  end
  subDirs = {dirWithSubFolders(dirIndex).name};  %# Get a list of the subdirectories
  validIndex = ~ismember(subDirs,{'.','..'});  %# Find index of subdirectories
                                               %#   that are not '.' or '..'
  for iDir = find(validIndex)                  %# Loop over valid subdirectories
    nextDir = fullfile(dirName,subDirs{iDir});    %# Get the subdirectory path
    fileList = [fileList; getAllFiles(nextDir, fileExtension, appendFullPath)];  %# Recursively call getAllFiles
  end

end

运行代码的示例:

fileList = getAllFiles(dirName, '*.xml', 0); %#0 is false obviously

8
你可以使用正则表达式或strcmp函数来排除...。 或者,如果你只想要目录中的文件而不是文件夹,你可以使用isdir字段。
list=dir(pwd);  %get info of files/folders in current directory
isfile=~[list.isdir]; %determine index of files vs folders
filenames={list(isfile).name}; %create cell array of file names

或者将最后两行合并为一行:
filenames={list(~[list.isdir]).name};

列出目录中除了“.”和“..”之外的文件夹列表

dirnames={list([list.isdir]).name};
dirnames=dirnames(~(strcmp('.',dirnames)|strcmp('..',dirnames)));

从这一点开始,您应该能够将代码放入嵌套的for循环中,并继续搜索每个子文件夹,直到您的dirnames对于每个子目录都返回一个空单元格。

@Runner:如果您使用一些for和while循环,它会工作...但是我现在太懒了,不想实现。 - Doresoom
即使它并没有完全回答问题,但它确实提供了一种快速筛选目录的方法。+1 - jhfrontz

7

这个答案并没有直接回答问题,但可能是一个创意解决方案。

我赞同gnovice的解决方案,但我想提供另一种解决方案:使用您操作系统的特定命令:

tic
asdfList = getAllFiles('../TIMIT_FULL/train');
toc
% Elapsed time is 19.066170 seconds.

tic
[status,cmdout] = system('find ../TIMIT_FULL/train/ -iname "*.wav"');
C = strsplit(strtrim(cmdout));
toc
% Elapsed time is 0.603163 seconds.

优点:

  • 非常快(在我的情况下,对于一个包含18000个文件的数据库,运行在Linux上)。
  • 你可以使用经过充分测试的解决方案。
  • 你不需要学习或重新发明用于选择例如*.wav文件的新语法。

缺点:

  • 你不是独立于系统的。
  • 你依赖于可能很难解析的单个字符串。

3
我不知道单一功能的方法,但是你可以使用genpath来递归列出子目录。返回的列表是一个分号分隔的目录字符串,所以你需要使用strread来分离它,例如: dirlist = strread(genpath('/path/of/directory'),'%s','delimiter',';') 如果你不想包括给定的目录,请删除dirlist的第一个条目,即dirlist(1)=[];,因为它总是第一个条目。
然后使用循环的dir来获取每个目录中的文件列表。
filenamelist=[];
for d=1:length(dirlist)
    % keep only filenames
    filelist=dir(dirlist{d});
    filelist={filelist.name};

    % remove '.' and '..' entries
    filelist([strmatch('.',filelist,'exact');strmatch('..',filelist,'exact'))=[];
    % or to ignore all hidden files, use filelist(strmatch('.',filelist))=[];

    % prepend directory name to each filename entry, separated by filesep*
    for f=1:length(filelist)
        filelist{f}=[dirlist{d} filesep filelist{f}];
    end

    filenamelist=[filenamelist filelist];
end

filesep函数返回MATLAB运行平台的目录分隔符。

这将在单元格数组filenamelist中给出具有完整路径的文件名列表。虽然不是最简洁的解决方案,但也能起到帮助作用。


出于性能原因,我不想使用 genpath,它会进行两次搜索。 - Gtker
2
使用GENPATH的一个缺点是它只包括MATLAB路径上允许的子目录。例如,如果您有名为“private”的目录,则不会包括在内。 - gnovice

1
这是一个方便的函数,用于获取根文件夹中指定格式(通常为.mat)的文件名!
    function filenames = getFilenames(rootDir, format)
        % Get filenames with specified `format` in given `foler` 
        %
        % Parameters
        % ----------
        % - rootDir: char vector
        %   Target folder
        % - format: char vector = 'mat'
        %   File foramt

        % default values
        if ~exist('format', 'var')
            format = 'mat';
        end

        format = ['*.', format];
        filenames = dir(fullfile(rootDir, format));
        filenames = arrayfun(...
            @(x) fullfile(x.folder, x.name), ...
            filenames, ...
            'UniformOutput', false ...
        );
    end

在您的情况下,您可以使用以下代码片段 :)
filenames = getFilenames('D:/dic/**');
for i = 1:numel(filenames)
    filename = filenames{i};
    % do your job!
end

0

通过稍微修改但几乎相同的方法来获取每个子文件夹的完整文件路径

dataFolderPath = 'UCR_TS_Archive_2015/';

dirData = dir(dataFolderPath);      %# Get the data for the current directory
dirIndex = [dirData.isdir];  %# Find the index for directories
fileList = {dirData(~dirIndex).name}';  %'# Get a list of the files
if ~isempty(fileList)
    fileList = cellfun(@(x) fullfile(dataFolderPath,x),...  %# Prepend path to files
        fileList,'UniformOutput',false);
end
subDirs = {dirData(dirIndex).name};  %# Get a list of the subdirectories
validIndex = ~ismember(subDirs,{'.','..'});  %# Find index of subdirectories
%#   that are not '.' or '..'
for iDir = find(validIndex)                  %# Loop over valid subdirectories
    nextDir = fullfile(dataFolderPath,subDirs{iDir});    %# Get the subdirectory path
    getAllFiles = dir(nextDir);
    for k = 1:1:size(getAllFiles,1)
        validFileIndex = ~ismember(getAllFiles(k,1).name,{'.','..'});
        if(validFileIndex)
            filePathComplete = fullfile(nextDir,getAllFiles(k,1).name);
            fprintf('The Complete File Path: %s\n', filePathComplete);
        end
    end
end  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接