如果我使用fread会得到错误,而使用read时没有错误

时间:2014-12-20 14:13:02

标签: c++ fread

我正在尝试使用缓存对磁盘I / O进行一些实验而不使用它。为了直接从磁盘执行读取,我使用O_DIRECT标志打开文件(定义变量DISK_DIRECT)。

现在if下面的两个分支应该执行相同的操作,区别在于一个是由缓存帮助而另一个不是。 我尝试访问的文件存储在磁盘上,并且不会随时间变化。 此外,两个分支也可以访问相同的文件。

在某些地方,当我使用fread时,我得到ferror()是真的。当我使用阅读时,一切都很顺利。

我确定他们访问相同的文件。 你知道为什么会这样吗?

修改

好的,我在这里发布一个最小的例子。我使用的代码是:

#include <iostream>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <sstream>


using namespace std;

typedef float fftwf_complex [2] ;

void fetch_level(unsigned long long tid, unsigned short level, fftwf_complex* P_read, fftwf_complex* P_fread, int n_coeff_per_level, FILE** files_o_direct, fstream* & files) {

  int b_read;
  fseek(files_o_direct[level],(long int) (tid * sizeof(fftwf_complex)*n_coeff_per_level), SEEK_SET);


  b_read = fread(reinterpret_cast<char*>(P_fread),sizeof(fftwf_complex), n_coeff_per_level,files_o_direct[level]);

  if(b_read == 0){ 
    cerr << "nothing read\n";

  }

  files[level].seekg((streamoff) (tid * sizeof(fftwf_complex)*n_coeff_per_level), files[level].beg);

  files[level].read(reinterpret_cast<char*>(P_read), 
            sizeof(fftwf_complex) * n_coeff_per_level);

}

void open_files (fstream* & files){

  for(int i=0; i<1;i++) {
    std::ostringstream oss;
    oss << "./Test_fread_read/1.txt.bin";

    files[i].open(oss.str().c_str(),
          std::ios::in | std::ios::out | 
          std::ios::binary | std::ios::ate);
    if (!files[i])
      {
    cerr << "fstream could not open " << oss.str() << endl;
      }
  }
}

void open_files_o_direct (FILE** files_o_direct, int* fd){

  for(unsigned int i=0;i<1; i++){
    std::ostringstream oss;
    oss << "./Test_fread_read/1.txt.bin";
    fd[i]=open(oss.str().c_str(), O_RDONLY | O_DIRECT);
    files_o_direct[i] = fdopen(fd[i], "rb");

    if(!files_o_direct[i])
      cerr << "Could not open " << oss.str() << endl;

  }
}

int close_files(FILE** files_o_direct, int* fd, fstream* & files) {

  for(unsigned int i=0; i<1; i++){
    //#if defined (DISK_DIRECT)
    if(files_o_direct[i])
      close(fd[i]);
    //#else
    if(files[i].is_open())
      files[i].close();
    //#endif
  }

  return 0;
}

int main(){

  FILE**files_o_direct = new FILE* [256];
  fstream* files = new fstream [256];
  int * fd = new int [256];


  fftwf_complex * P_read =  new fftwf_complex [1];
  fftwf_complex * P_fread =  new fftwf_complex [1];

  open_files_o_direct(files_o_direct, fd);
  open_files(files);

fetch_level(2, 0, P_read, P_fread, 1, files_o_direct, files);
  cout << "P_read: " << P_read[0][0] << " P_fread: " << P_fread[0][0] << endl;
  cout << "P_read: " << P_read[0][1] << " P_fread: " << P_fread[0][1] << endl;
fetch_level(7, 0, P_read, P_fread, 1, files_o_direct, files);
  cout << "P_read: " << P_read[0][0] << " P_fread: " << P_fread[0][0] << endl;
  cout << "P_read: " << P_read[0][1] << " P_fread: " << P_fread[0][1] << endl;
fetch_level(8, 0, P_read, P_fread, 1, files_o_direct, files);
  cout << "P_read: " << P_read[0][0] << " P_fread: " << P_fread[0][0] << endl;
  cout << "P_read: " << P_read[0][1] << " P_fread: " << P_fread[0][1] << endl;


  close_files(files_o_direct, fd, files);

  delete [] P_read;
  delete [] P_fread;
  delete [] files;
  delete [] files_o_direct;

  return 0;
}

,访问的文件是:

0.133919 0.0458176 
1.67441 2.40805 
0.997525 -0.279977 
-2.39672 -3.076 
-0.0390913 0.854464 
-0.0176478 -1.3142 
-0.667981 -0.486272 
0.831051 0.282802 
-0.638032 -0.630943 
-0.669854 -1.49762 

以二进制格式存储,可以从here: 1.txt.bin下载。

我得到的输出是:

nothing read
P_read: 0.997525 P_fread: 0
P_read: -0.279977 P_fread: 0
nothing read
P_read: 0.831051 P_fread: 0
P_read: 0.282802 P_fread: 0
nothing read
P_read: -0.638032 P_fread: 0
P_read: -0.630943 P_fread: 0

即使我将fftwf_complex的类型从float [2]更改为simple float,问题仍然存在。 如果我删除了fseek行,一切正常。

2 个答案:

答案 0 :(得分:0)

if (b_read == 0)将在文件末尾为true,您将进入此分支

if(ferror(this->files_o_direct[level]))
    fseek(this->files_o_direct[level], 0, SEEK_END); //ftell here returns 4800000 
cerr << "nothing read\n";

即使ferror返回0,仍然会到达文件末尾

fseek(this->files_o_direct[level], 0, SEEK_END);

没有意义,"nothing read\n"将输出或不输出ferror返回非零值。

来自manual page

  

fread()不区分文件结束和错误,并且调用者必须使用feof(3)和ferror(3)来确定发生了什么。

所以你必须检查feof,如果它是假的,你使用ferror

答案 1 :(得分:0)

对于谁可能在这里遇到同样的问题,答案是:

  

O_DIRECT标志可能会对长度和长度施加对齐限制        用户空间缓冲区的地址和I / O的文件偏移量。在Linux中         对齐限制因文件系统和内核版本而异         可能完全没有。但目前没有         独立于文件系统的接口,供应用程序发现这些         对给定文件或文件系统的限制。一些文件系统         提供他们自己的接口,例如         xfsctl(3)中的XFS_IOC_DIOINFO操作。

  Under Linux 2.4, transfer sizes, and the alignment of the user buffer
  and the file offset must all be multiples of the logical block size
  of the filesystem.  Since Linux 2.6.0, alignment to the logical block
  size of the underlying storage (typically 512 bytes) suffices.  The
  logical block size can be determined using the ioctl(2) BLKSSZGET
  operation or from the shell using the command:

      blockdev --getss 

linux reference page