How to read multiple huge text files, the fastest way?
Show older comments
Hi All,
I am quite new to Matlab and sorry for the naive question. Request your kind help on my problem as given below.
I have around 10,000 input text files to read and process in Matlab. The text file contains only numerical data but each file is around 12-15MB and hence the total size of the input is around 125~150GB.
First, I tried to use fgetl() to read each line from each file and iterate but it took very long. So I have modified the input text file format as a set of numbers separated by white spaces and used fscanf() to read to a matrix of size [1 inf]. Still it takes couple of hours to read all the 10,000 files.
I have tried to use parfor loop and ran the code in a matlabpool of cluster size 8 (the system is a linux server - 4 processors, each dual code). Even then, it takes more than 2 hours to read all the files.
Could anyone kindly let me know what is the fastest way to read this much huge data in Matlab? My requirement is to read this much data (125~150 GB) in a couple of minutes.
Note: I can change the format of the input text file to achieve the highest possible file read. But I would like to read the inputs as numbers only (not string) as during processing str2double() takes much time.
Thanks a million in advance. Expecting your expert advice.
Warm Regards
Anand Uthaman
7 Comments
Jason Ross
on 18 Mar 2011
What sort of storage technology are you using in your system and where does the data live? Even simple operations like copying 125-150 GB of data on local storage can take minutes to accomplish -- and you aren't even doing anything with the data.
If you are storing the data on a network filesystem, simply accessing the data is going to take a significant amount of time, depending on the capability of your network and file server -- more than local disk.
Of course, you can get around the above problems by using multiple hosts to access the data on a network -- but you would need a pretty decent bit of hardware to be able to serve up 125 GB in a couple of minutes.
In a related question, how are the 10,000 files organized? In my experience, once directory sizes (number of files in them) begin to grow beyond a few thousand files, the time to do anything in a directory starts to grow by a significant amount. If you can reduce the sheer number of files by concatenating them in some manner or by utilizing a directory structure to keep the number of files in each directory down, this might help. If you Google around for your filesystem type and see if it has documented limits or recommended limits, this might help you with your problem.
Anand Uthaman
on 18 Mar 2011
Jason Ross
on 18 Mar 2011
Memory latency is measured in nanoseconds and disk access in milliseconds, so pretty much by definition the disk I/O is going to be more expensive. If you start loading up the machine enough to cause it to swap out, you'll be paying even more of a penalty.
Since you have full control over the file format and data, you might look into varying the file sizes to find the optimal file size for your problem. As Fangjun Jiang suggests below, doing selective reads and working on parts of the data could improve performance.
Jason Ross
on 18 Mar 2011
You might also consider looking into using a SSD disk in the system versus the conventional drive. The price of a SSD has dropped into the realm of the possible for more people nowadays. Conventional drives still hold the upper hand for storage size versus cost, but the SSD's access time is pretty darn amazing.
Anand Uthaman
on 18 Mar 2011
Jason Ross
on 18 Mar 2011
The way to know if you are swapping is to watch something like "top". It seems that you might want to look somewhere less than 10,000 and more than 100 to see if you can do better :)
Anand Uthaman
on 18 Mar 2011
Accepted Answer
More Answers (2)
Matt Tearle
on 18 Mar 2011
0 votes
If you have to read it as ASCII, your best option is textscan, which will read directly into whatever numeric format you specify ( %f for double, %d for integer, etc).
1 Comment
Anand Uthaman
on 18 Mar 2011
bim
on 25 Dec 2022
0 votes
I have been using importdata for textfiles, but it is very slow for text unless you rename all the files to '.txt'.
The function below seems to do the job for structured text files.
The structure the function can handle is shown at the bottom the function: it only works for tables of float numbers
Let me know whether this works well.
%% READTEXTFILE reads text files without any checks
% READTEXTFILE reads from file and immediately filters out the selectColumns
% READTEXTFILE can read any number of headerlines, but
% the headerlines must contain both nRows='a number' and 'nColumns=a number' in separate lines
% the lines containing nRows and nColumns must not contain any spaces
%
% parameter filename = if the selected file is not a text file, the function will fail
% the extension of the filename is ignored and does not need to be present
% parameter selectedcolumns = header names of columns to be selected from the file
% e.g., selectedcolumns = {'time', 'column_3'}
%
% The read data is returned in a struct c
% content.data = the actual data as a matrix
% content.colheaders = the headers of the remaining columns
% content.colheaders == selectedcolumns
% content.textdata == content.colheaders
%
function content=readtextfile(varargin) % filename,selectedcolumns
tic
selectedcolumns={};
if nargin>2 || nargin ==0
error('readtextfile: too many or too few arguments');
elseif nargin ==2
selectedcolumns=varargin{2};
end
filename=varargin{1};
fid = fopen(filename,'rt');
file.title = fgetl(fid);
file.nrows=string([]);
file.ncolumns=string([]);
line = string(fgetl(fid));
while line ~= "endheader"
if length(file.nrows)==0
file.nrows=regexp(line,'^nRows=(?<nrows>\d+)$','tokens','once');
end
if length(file.ncolumns)==0
file.ncolumns=regexp(line,'^nColumns=(?<ncolumns>\d+)$','tokens','once');
end
line = string(fgetl(fid));
end
file.nrows=str2num(file.nrows);
file.ncolumns=str2num(file.ncolumns);
fsColHeaders = repmat([' %s'],1,file.ncolumns);
colHeaders = textscan(fid,fsColHeaders,1,'EndOfLine','\r\n','MultipleDelimsAsOne',1); % 3rd param (N) == 1 --> read once
fsData = repmat([' %f'],1,file.ncolumns);
fileData = textscan(fid,fsData,'EndOfLine','\r\n','MultipleDelimsAsOne',1); % 3rd param (N) missing --> read until end of file
colHeaders =cellfun(@char,colHeaders,'UniformOutput',false);
[~,copiedColumns] = ismember(selectedcolumns,colHeaders);
if length(copiedColumns)>0
newMatrix= zeros(file.nrows,nnz(copiedColumns));
iNewColumns=1;
for iCopiedColumns = copiedColumns
if iCopiedColumns>0
newMatrix(:,iNewColumns) = fileData{iCopiedColumns};
% newHeaders is not necessary, since it corresponds to selectedcolumns
% but it is is helpful in checking proper operation of the function
newHeaders(:,iNewColumns) = colHeaders(iCopiedColumns);
iNewColumns=iNewColumns+1;
end
end
else
newMatrix = cell2mat(fileData);
newHeaders = colHeaders;
end
fclose(fid);
content.data = newMatrix;
content.textdata = newHeaders;
content.colheaders = newHeaders;
toc
end
% example of possible headerlines
%{
the title
nRows=437
nColumns=17
any number of lines
endheader
time column_1 column_2 column_3 ...
0.001 0.1234 0.3456 0.7891
0.002 0.2234 0.4456 0.8891
%}
Categories
Find more on MATLAB Parallel Server in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!