繁体   English   中英

如果我使用fread会出错,而使用read则不会出错

[英]get error if i use fread, while no error using read

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

现在,如果在下面,则if的两个分支应该执行相同的操作,不同之处在于一个由缓存帮助,另一个不由缓存帮助。 我尝试访问的文件存储在磁盘上,并且它们不会随时间变化。 同样,两个分支访问相同的文件。

在这里的某个时候,当我使用fread时,我会得到ferror()为真。 当我使用read时,一切都很好。

我确定他们访问相同的文件。 您知道为什么会发生这种情况吗?

编辑

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

#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 

它以二进制格式存储,可以从此处下载: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]更改为简单float,问题仍然存在。 如果我删除fseek行,一切正常。

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返回非零值。

手册页

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

因此,您必须检查feof ,如果它是假的,则使用ferror

对于可能遇到相同问题的人,这里有答案:

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参考页

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM