【问题标题】:get error if i use fread, while no error using read如果我使用 fread 会出错,而使用 read 不会出错
【发布时间】:2014-12-20 14:13:02
【问题描述】:

我正在尝试使用缓存而不是使用缓存对磁盘 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 

以二进制格式存储,可从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 行一切正常。

【问题讨论】:

  • 错误号是多少?你检查了吗?
  • MCVE 将在很大程度上证明您遇到的问题,并且鉴于您的主张 freadstd::istream::read 是唯一的区别,提供微不足道的。发布的代码不仅不可编译,而且不是范围平衡的。 fread 调用在 } 之前包含 fseekfreadstd::istream::seekgstd::istream::read 之间有一个 }。显然你遗漏了something
  • 我尝试使用 explain_fread 但出现“未定义引用”错误,我不知道是不是因为您需要链接库,但我没有找到任何关于那。还有其他方法可以获取错误号吗?
  • @WhozCraig 这是一个错字,我已经更正了
  • @Sergio “我尝试使用 explain_fread ...” 你甚至没有在你的问题中提到这一点。您是否查看了此问答如何解决该问题:stackoverflow.com/questions/12573816/…

标签: c++ fread


【解决方案1】:

这个if (b_read == 0),在文件末尾为真,你会进入这个分支

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

【讨论】:

  • 我添加了那行代码以在调试时检查文件大小,并确保 fseek 不在文件末尾
  • 你是如何使用它来达到这个目的的?为此,您必须检查 feof 而不是 ferror
  • 代码中有另一个 fseek 调用,我在那里检查 ftell(如 cmets 中所写),然后在第二个 fseek 调用中检查 ftell。我可以看出 fseek 不在文件末尾
  • ftell 不会告诉您您是否在文件末尾feof 会,您也可以发布这些行吗?
  • ftell 告诉您从文件开头有多少字节,因此如果您使用 fseek 在文件末尾检查 ftell 的值,您将获得文件的大小.如果在此之前你已经检查过你在哪个位置,你就可以说你是否在文件的末尾
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 2017-08-04
    • 1970-01-01
    • 2017-01-26
    • 2016-05-03
    • 2021-09-24
    • 1970-01-01
    相关资源
    最近更新 更多