您的位置:

深度理解Matlab fseek

一、fseek函数基本介绍

fseek函数是Matlab中常用的文件操作函数之一,能够实现文件内读取位置的指定。

fid = fopen('test.txt', 'r');
fseek(fid, offset, origin);

其中,'test.txt'是待操作文件名称,'r'表示以只读方式打开文件;

offset是需要移动的字节数,可以为正数、负数或零;

origin是移动的起始位置,可以是三个值:

  • SEEK_SET:表示从文件之始开始偏移;
  • SEEK_CUR:表示从当前位置开始偏移;
  • SEEK_END:表示从文件之末开始偏移。

这样就可以方便地对文件流进行跳跃定位,比如在读取文件时,我们可以跳过前面若干字节的无用信息,定位到读取所需信息的位置。

二、fseek函数的使用方法

1. 文件指针的创建与移动

下面我们以图像文件为例,演示使用fseek函数定位到特定像素点的方法。

% 打开图片并进行处理
img = imread('peppers.png');
figure, imshow(img), title('Original image');
 
% 创建文件指针
fid = fopen('peppers.txt', 'w');

% 将图片数据写入指针所指定的文件
fwrite(fid, img, 'uint8');

% 将指针指向特定位置,即第400行,第1列
fseek(fid, 400 * size(img,1) + 1, 'bof');

% 从当前位置开始,读取指定数量的数据
data = fread(fid, 10);

% 关闭文件指针
fclose(fid);

% 显示读取的数据
disp(data);
 

在上面的代码中,我们使用了Matlab自带的peppers.png图片作为输入数据源,并把该图片的像素信息写入名为peppers.txt的文件中。

接着,我们利用fseek函数将文件指针定位到第400行第1列的位置,即第400行首像素。

最后,我们使用fread函数从定位位置开始,读取10个数据,并打印输出。

2. 移动多个数据块

基于fseek函数的定位操作,我们也可以一次性定位到多个数据块,并进行连续读取。

% 创建文件指针
fid = fopen('data.txt', 'w');

% 写入数据
data = 1:20;
fwrite(fid, data, 'uint16');

% 将指针移动至第1个数据块
offset = 4;
fseek(fid, offset, 'bof');

% 从当前位置开始连续读取3个数据块并打印输出
data = fread(fid, 3, 'uint16');
fclose(fid);

% 打印读取的数据
disp(data);
 

本例中,我们创建了一个名为data.txt的文件,并写入包含1~20个数值的数据块。接着,我们将文件指针向后移动4个数据块,即从第5个到第8个数据块的位置,然后再读取3个数据块的内容。

3. 跨文件移动指针

fseek函数不仅可以移动文件内部的指针,也可以用于跨文件移动指针。

% 创建两个文件指针
fid1 = fopen('data1.txt', 'w');
fid2 = fopen('data2.txt', 'w');

% 在文件1中写入数据
data = 1:5;
fwrite(fid1, data, 'uint8');

% 在文件2中写入数据
data = 'CADT';
fwrite(fid2, data, 'char');

% 移动文件指针到文件2的起始位置
fseek(fid2, 0, 'bof');

% 把文件1中的数据复制到文件2
data = fread(fid1, inf, 'uint8');
fwrite(fid2, data, 'uint8');

% 关闭文件指针
fclose(fid1);
fclose(fid2);

% 读出文件2中的所有数据
fid2 = fopen('data2.txt', 'r');
data = fread(fid2, inf, 'char');
fclose(fid2);

% 打印读取的数据
disp(data);
 

本例中,我们分别创建了data1.txt和data2.txt两个文件,并在各自的文件中写入了数据。然后我们利用fseek函数将文件指针从data1.txt跳转到data2.txt,并把data1.txt中的数据复制到data2.txt中。

最后,我们读取data2.txt中的所有数据,并打印出来。

三、fseek函数的错误处理

在使用fseek函数时,可能面临文件无法打开、指针越界等问题。这时需要及时处理错误信息,确保程序顺利运行。

% 打开文件
fid = fopen('nus.txt', 'r');

% 如果成功打开文件,就将指针移动到末尾
if fid ~= -1
    fseek(fid, 0, 'eof');
    fileSize = ftell(fid);
    fprintf('File size is %d bytes.\n', fileSize);
    
    % 关闭文件指针
    fclose(fid);
else
    fprintf('File could not be opened.\n');
end
 

在上面的例子中,我们利用fopen函数打开名为nus.txt的文件,并检查文件是否成功打开。如果成功打开,则移动指针到末尾,获取文件大小并关闭文件指针;如果文件无法打开,则输出错误信息。

四、fseek函数实际应用场景

fseek函数的跳跃定位功能,在实际应用中十分重要。我们可以利用fseek函数实现对大型文件的逐块读取,实现更高效的文件读写操作。

下面以读取文本文件的方式为例,演示fseek函数实际应用。

function readData(filename, blockSize)
% 打开文件
fid = fopen(filename, 'r');

% 如果成功打开文件,就开始读取
if fid ~= -1
    % 获取文件总大小
    fseek(fid, 0, 'eof');
    fileSize = ftell(fid);
    
    % 从文件开始处开始读取
    fseek(fid, 0, 'bof');
    blockNum = ceil(fileSize / blockSize);
    
    % 逐块读取文件
    for i = 1:blockNum
        curBlock = fread(fid, blockSize, '*char');
        fprintf('%s', curBlock);
        fseek(fid, blockSize, 'cof');
    end
    
    % 关闭文件
    fclose(fid);
else
    fprintf('File could not be opened.\n');
end 

在上述代码中,我们定义了一个名为readData的函数,用于按块读取文本文件。函数有两个输入参数,filename表示文件名称,blockSize表示每个数据块的大小。

首先,我们打开文件并检查是否成功打开。如果打开成功,就通过fseek函数获取文件总大小,并将指针移动到文件的开始位置。

接着,我们设定块数与文件大小之间的关系,并逐块读取文件。对于每个数据块,我们使用fread函数从文件中读取blockSize大小的数据,并用fprintf函数将读取的数据打印到屏幕上。

最后,我们使用fseek函数将文件指针移动至下一块数据所在位置,继续读取数据。如果读取完毕,则关闭文件。

五、总结

本文从fseek函数的基本介绍、使用方法、错误处理和实际应用场景等多个方面对Matlab fseek进行了详细的阐述。fseek函数的跳跃定位功能,为我们处理大型文件和数据流提供了便利,值得熟练掌握。