MatLab list files (excluding directories) in a folder - matlab

So I know I can list all the files and directories in my current folder using functions like dir() or ls(), and I know once listed, I can tell them from each other with the field isdir.
But is there a way to exclude the directories from the very beggining and list the files alone?
Even better, is there a way to exclude the current . and parent .. directories -that will (of course) show everytime- and list every other file and directory? Seriously, who uses ls() wondering if . is there?

The output of dir is whatever the operating system is feeding it. So it might be different depending on what system you're running. Here is my approach to that:
list=dir();
CleanList=setdiff({list.name},{'.','..'})';

I'm not sure if there is a built in method for this, but why not write a custom function to do what you want?
Such as:
function list = files_dir(varargin)
% Similar functionality to 'dir', but only returns files (no folders)
list = dir(varargin{:});
list([list.isdir]) = [];
You can then customise this to perform other functionality, such as excluding hidden files.
And for your second request, where directories '.' and '..' are excluded:
function list = dir_exclude_self(varargin)
% same as 'dir', but doesn't return '.' or '..'
list = dir(varargin{:});
self_indices = ismember({list.name}, {'.', '..'});
list(self_indices) = [];
If you put functions like this in a specific place on your computer you can ensure they are always available to use by adding them to the MATLAB path in your startup.m file.

Related

determine if the file is empty and separate them into different file

The goal of my code is to look into a certain folder and create a new text file with a list of names of all the files that aren't empty in that folder written to a new file, and the list of names of all the empty files (no text) into another folder. My current code is only able to create a new text file with a list of names of all the files (regardless of its content) written to a new file. I want to know how to set up if statement regarding the content of the file (array).
function ListFile
dirName = '';
files = dir(fullfile(dirName,'*.txt'));
files = {files.name};
[fid,msg] = fopen(sprintf('output.txt'),'w+t');
assert(fid>=0,msg)
fprintf(fid,'%s\n',files{:});
fclose(fid);
EDIT: The linked solution in Stewie Griffin's comment is way better. Use this!
A simple approach would be to iterate all files, open them, and check their content. Caveat: If you have large files, this approach might be memory intensive.
A possible code for that could look like this:
function ListFile
dirName = '';
files = dir(fullfile(dirName, '*.txt'));
files = {files.name};
fidEmpty = fopen(sprintf('output_empty_files.txt'), 'w+t');
fidNonempty = fopen(sprintf('output_nonempty_files.txt'), 'w+t');
for iFile = 1:numel(files)
content = fileread(files{iFile})
if (isempty(content))
fprintf(fidEmpty, '%s\n', files{iFile});
else
fprintf(fidNonempty, '%s\n', files{iFile});
end
end
fclose(fidEmpty);
fclose(fidNonempty);
I have two non-empty files nonempty1.txt and nonempty2.txt as well as two empty files empty1.txt and empty2.txt. Running this code, I get the following outputs.
Debugging output from fileread:
content =
content =
content = Test
content = Another test
Content of output_empty_files.txt:
empty1.txt
empty2.txt
Content of output_nonempty_files.txt:
nonempty1.txt
nonempty2.txt
Matlab isn't really the optimal tool for this task (although it is capable). To generate the files you're looking for, a command line tool would be much more efficient.
For example, using GNU find you could do
find . -type f -not -empty -ls > notemptyfiles.txt
find . -type f -empty -ls > emptyfiles.txt
to create the text files you desire. Here's a link for doing something comparable using the windows command line. You could also call these functions from within Matlab if you want to using the system command. This would be much faster than iterating over the files from within Matlab.

How to list down mat files with a specific prefix name?

I have a folder of images saved as .mat files files with the following names:
image-001-001.mat,image-001-002.mat,......., image-001-102.mat, image-002-001.mat,image-002-002.mat, ....,image-002-090.mat, etc.
I want to group the file names for each prefix. For example, list down all files that starts with image-001- prefix and list all images with image-002- and etc. for all files in the folder. I need the images of each group separately and do some processing on them.
Could someone please give some hints how can I do it?
Thanks in advance
See the documentation for dir, specifically the mention of wildcards.
You can get a list of .mat files which start with image-001 using
files_001 = dir('C:\myfolder\image-001*.mat');
% or if it's in the current directory then simply
% files_001 = dir('image-001*.mat');
To loop over several prefixes, you could use
prefixes = {'image-001', 'image-002', 'image-003'};
files = cell(numel(prefixes), 1);
for p = 1:numel(prefixes)
files{p} = dir([prefixes{p}, '*.mat']);
end
Aside:
If your prefixes really are that similar / ordered, there are many ways (e.g. using strcat) to quickly make the prefixes cell array.
YOu can pick all the images with start with image-001-xxx.mat as below:
files1 = dir('image-001*') ;

How can I get a part of partfile?

This is probably a very simple question, but I am not able to find a straightforward solution.
[pathstr,name,ext] = fileparts('/xaaa/Data/Q2/CONUS/2002/PRECIPRATE.20020401.000000.tif')
Obviously, fileparts gives /xaaa/Data/Q2/CONUS/2002/
But I only want to access /xaaa/Data/Q2/CONUS/ and disregard the last section.
One way to do it is simply count the letters parthstr(1:20). But there must be an elegant alternative.
The most robust way to get a parent folder is to use '..' to access the folder above a provided folder. This is because it is independent of whether you specify an absolute or relative path as the input.
parent = fullfile(folder, '..');
In your case, since you have a filename and you want to get the parent, you can add a 'fileparts' call to that to get the direct parent folder, then pass it to the above.
parent = fullfile(fileparts(filename), '..');
This is more robust because it allows you to specify a relative file path such as 2002/PRECIPRATE.20020401.000000.tif which could fail if you tried to call fileparts multiple times.
If you only have a filename (with no directories because you're in the folder where the file is), you can use which to get an absolute path to the file.
parent = fullfile(fileparts(which(filename)), '..');
One simple way is to repeat the use of fileparts():
>> [pathstr,name,ext] = fileparts('/xaaa/Data/Q2/CONUS/2002/PRECIPRATE.20020401.000000.tif');
>> [parent_pathstr, name, ~] = fileparts(pathstr)
parent_pathstr =
/xaaa/Data/Q2/CONUS
name =
2002
Note: using the tilde ~ just ignores the file extension for the second call to fileparts() because you don't expect an extension.
There are three answers proposed already, but I do believe there's a better solution. I would match .*(?=/.*/) pattern using regexp, like this:
>> originalPath = '/xaaa/Data/Q2/CONUS/2002/PRECIPRATE.20020401.000000.tif';
>> res = char(regexp(originalPath, '.*(?=/.*/)', 'match'))
res =
/xaaa/Data/Q2/CONUS
If you need to go n levels deeper, just keep adding .*/ for each level, e.g.
>> res = char(regexp(originalPath, '.*(?=/.*/.*/)', 'match'))
res =
/xaaa/Data/Q2
For the OS-agnistic version, or if your path contains some mixture of back-slashes and forward-slashes, you can use the following regex: '.*(?=[/\\].*[/\\])'. Once again, to go several levels deper, just add an extra .*[/\\] for each level.
The benefit over using strsplit and fileparts is that you don't need to iterate anything - you get the answer with one simple regex.
Regarding .. - I myself used this solution for a long time for generating Matlab Path dynamically. However Matlab is sometimes not able to handle breakpoints correctly in the files that have .. in their path. To be exact, if you place a breakpoint in such a file, Matlab would ignore it unless there's another breakpoint that is triggered first (which is not in a file with .. in path).
It obviously handles relative paths as well.

How to get relative path to folder containing a .m file

I write code where I load a lot of project data. I want to keep my pathnames in the code relative to some location of this project on the disk, i.e. not having it configured or hard-coded.
Is there function in matlab to do some like this?
In python I would write:
ROOT = os.path.dirname(__file__)
The best way to do this is to combine fileparts with mfilename('fullpath'). (All examples assume the executing m-file containing these statements lives in /home/suever/code/stackoverflow.m)
mfiledir = fileparts(mfilename('fullpath'));
/home/suever/code
Then you can use fullfile to construct any paths you need from that. Now if you have a file (data.mat) stored in the same directory:
filename = fullfile(mfiledir, 'data.mat');
/home/suever/code/data.mat
Of if the file is actually in the parent directory.
filename = fullfile(mfiledir, '..', 'data.mat');
/home/suever/data.mat
If you want just the parent directory that an m-file is in, you can apply fileparts twice and only keep the second output.
[~, reldir] = fileparts(fileparts(mfilename('fullpath')));
code
I would recommend the use of full paths in the first examples as those are completely independent of the user's current working directory.
A better recipe to organize your code is to have a function like this:
function [ path ] = get_path()
path = [regexprep(mfilename('fullpath'), ['\' filesep '[\w\.]*$'],'') filesep];
end
You drop it inside +foo/get_path.m file and than call something like foo.get_path() that returns the path to +foo folder.

How to remove a pattern from filename in Matlab

I'd like to remove '-2' from the filenames looking like this:
EID-NFBSS-2FE454B7-2_TD.eeg
EID-NFBSS-2FE454B7-2_TD.vhdr
EID-NFBSS-2FE454B7-2_TD.vmrk
EID-NFBSS-3B3BF9FA-2_BU.eeg
EID-NFBSS-2FE454B7-2_PO.txt
So as you may see the names of the files are different and there are different kind of extensions as well. All what I want to do is remove '-2' from all of the filenames. I was trying use this:
pattern = '-2';
replacement = '';
regexprep(filename,pattern,replacement)
and I got the results in the console, but after many attempts I have no idea how to 'say' to MATLAB switch the filnames in the same location.
#excaza hit it right on the money. You'll have to probe your desired directory for a list of files via dir, then loop through each filename and remove any occurrences of -2, then use movefile to rename the file, and delete to delete the old file.
Something like this comes to mind:
%// Get all files in this directory
d = fullfile('path', 'to', 'folder', 'here');
directory = dir(d);
%// For each file in this directory...
for ii = 1 : numel(directory)
%// Get the relative filename
name = directory(ii).name;
%// Replace any instances of -2 with nothing
name_after = regexprep(name, '-2', '');
%// If the string has changed after this...
if ~strcmpi(name, name_after)
%// Get the absolute path to both the original file and
%// the new file name
fullname = fullfile(directory, name);
fullname_after = fullfile(directory, name_after);
%// Create the new file
movefile(fullname, fullname_after);
%// Delete the old file
delete(fullname);
end
end
The logic behind this is quite simple. First, the string d determines the directory where you want to search for files. fullfile is used to construct your path by parts. The reason why this is important is because this allows the code to be platform agnostic. The delineation to separate between directories is different between operating systems. For example, in Windows the character is \ while on Mac OS and Linux, it's /. I don't know which platform you're running so fullfile is going to be useful here. Simply take each part of your directory and put them in as separate strings into fullfile.
Now, use dir to find all files in this directory of your choice. Replace the /path/to/folder/here with your desired path. Next, we iterate over all of the files. For each file, we get the relative filename. dir contains information about each file, and the field you want that is most important is the name attribute. However, this attribute is relative, which means that only the filename itself, without the full path to where this file is stored is given. After, we use regexprep as you have already done to replace any instances of -2 with nothing.
The next point is important. After we try and change the filename, if the file isn't the same, we need to create a new file by simply copying the old file to a new file of the changed name and we delete the old file. The function fullfile here helps establish absolute paths to where your file is located in the off-chance that are you running this script in a directory that doesn't include the files you're looking for.
We use fullfile to find the absolute paths to both the old and new file, use movefile to create the new file and delete to delete the old file.