2015-04-28 41 views
0
  1. 我遇到这个错误不是经常性的,无法重现它。
  2. 正在读取的文件是只读文件,无法删除或修改。
  3. 代码不完全一样,因为它是我正在编写的更大的东西的一部分,但这是造成问题的代码的重要部分。
  4. 此代码是用于说明目的,而不是复制,因为1点

我试图读取使用cpp文件读取stat和读取错误()

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <memory> 
#include <exception> 
#include <iostream> 
#include <glog/logging.h> 
using namespace std; 
int main() { 
    string fileName="blah"; 
    struct stat fileStat; 
    int status = ::stat(fileName.c_str(), &fileStat); 
    if (status != 0) { 
    LOG(ERROR) << "Error stating the file"; 
    } 
    size_t fileSize = fileStat.st_size; 
    // fileSize is 79626240. I am trying to read block starting from 
    // 67108864 bytes, so there will be 1251736 
    size_t fileBlockSize = 16 * 1024 * 1024; 
    size_t numBlocks = fileSize/fileBlockSize;  
    size_t offset = numBlocks; 
    size_t actualSize = fileSize - offset * fileBlockSize; 
    if (actualSize == 0) { 
     LOG(INFO) << "You read the entire file"; 
     return 1; 
    } 

    int fd = ::open(fileName.c_str(), O_RDONLY); 
    if (fd < 0) { 
     throw std::runtime_error("Error opening the file"); 
    } else if (offset > 0 && lseek(fd, offset, SEEK_SET) < 0) { 
    throw std::runtime_error("Error seeking the file"); 
    } 

    uint64_t readBlockSize = 256 * 1024;  
    char *data = new char[readBlockSize + 1]; 
    uint64_t totalRead = 0; 
    while (totalRead < actualSize) { 
     ssize_t numRead = ::read(fd, data, readBlockSize); 
     // Use the data you read upto numRead 
     if (numRead == 0) { 
     LOG(ERROR) << "Reached end of file"; 
     break; 
     } else if (numRead < 0) { 
     throw std::runtime_error("read unsuccessful"); 
     } 
     totalRead += numRead; 
    } 
    if (totalRead != actualSize) { 
     LOG(ERROR) << "Error reading the file"; 
    } 
} 

文件如果你想像我的文件切片成块的问题大小16 mybtes,然后阅读最后一个块。我正在以较小的尺寸在循环中读取该块,但是在阅读完整个块之前我获得了EOF。它可以发生stat报告的大小大于文件中数据的大小吗?

输出我看到:

Reached end of file 
Error reading the file 

我不需要替代解决方案,我可以做其他事情,如lseek的,但是我想,以知道到底为什么发生这种情况?

PS这不是因为磁盘上的块数。我使用st_size而已

+3

请给出一个最简单的例子,最好是自己编译的例子。我们都懂代码,但我们很少有人在英语课上取得好成绩。 – randomusername

+2

“我得到EOF”是什么意思?究竟什么操作正在返回什么值? –

+0

添加了更完整的代码片段。 EOF我的意思是文件结尾 –

回答

0

所以你的问题是:能规模报告fstat,或stat上只读不修改的文件是大于究竟会从文件读?

首先对read返回值(从手册页)的一些元素: 成功时,读取的字节返回的数量(零表示文件的结尾),以及文件位置由这个数字推进。如果这个数字小于所请求的字节数就不是错误的...错误时,返回-1,并且适当地设置errno

所以返回值是最大请求的大小,可以小于,其中0表示文件尾指示,-1表示错误指示。

手册页还表示读取的字节数少于请求的大小可能会发生,例如,因为现在实际上可用的字节数更少(可能因为我们接近文件结束,或者因为我们正在从管道或终端),或因为read()被信号中断。

所以,即使我永远无法看到,文档中的任何内容都不能保证即使读取文件,也会得到尽可能多的数据,除非已达到文件结尾。

但明确指出,返回值为0意味着您处于文件结尾。当你用0 == read(...)测试文件结尾时,一切正常。

对于你的问题:可以通过stat报告的大小与可以从文件中读取的字节数不同,答案是,除非文件系统损坏或存在物理读取错误。这是size成员的定义:的st_size域给出了文件的大小(如果它是一个普通文件或符号链接)以字节为单位(从stat手册页)

但我真的无法理解你的码。首先,我看到:

size_t fileSize = fileStat.st_size; 
// fileSize is 79626240. I am trying to read block starting from 
// 67108864 bytes, so there will be 1251736 
size_t fileBlockSize = 16 * 1024 * 1024; 
size_t numBlocks = fileSize/fileBlockSize;  
size_t offset = numBlocks; 
size_t actualSize = fileSize - offset * fileBlockSize; 

所以actualSize现在1251736当文件是79626240字节长。

后来,不actualSize发生了变化:

uint64_t totalRead = 0; 
while (totalRead < actualSize) { 
    ssize_t numRead = ::read(fd, data, readBlockSize); 
    ... 
    totalRead += numRead; 
} 
if (totalRead != actualSize) { 
    LOG(ERROR) << "Error reading the file"; 
} 

由于actualSize尽管它的名字是实际文件大小,你可以进入Error reading the file分支。但如果它发生在真正的文件大小上,请仔细检查您的文件系统。

+0

我知道cr == :: read(fd,data,actualSize)应该做什么。但我问,是否有可能获得比st_size更小的读取大小。就是那个问题。 –

+0

@NikunjYadav:如果这是问题,我的回答不是。看我的编辑。 –

2

您必须在文件上使用stat,最好使用fstat来避免TOCTOU竞争条件。

int fileDescriptor = -1; 
struct stat fileStat; 
std::vector<char> fileContent; 
std::string filename("test.txt"); 

fileDescriptor = open(filename.c_str(),O_RDONLY); 
// Do error check of fileDescriptor 
fstat(fileDescriptor,&fileStat); 
// Do error check of fstat 
fileContent.resize(fileStat.st_size); 
::read(fileDescriptor,fileContent.data(),fileStat.st_size); 

close(fileDescriptor); 

此外,考虑到读可以返回一个值比fileStat.st_size较小,你必须(在文件相当困难的I/O,与插座虽然是很常见的)阅读其余的字节,代码只是一个小例。

编辑

我与g++ -g -std=c++11 -lglog main.cpp复制你的代码和修改,以加载本地9MB文件,编译后,我已经安装在线路断点51

如果(totalRead!= actualSize)

这是从我的调试会话的结果:

(GDB)b main.cpp中:51断点1在0x4013fc:文件main.cpp中,线51

(GDB)R启动程序:/home/jpalma/Documents/functionTest/a.out

[使用libthread_db启用线程调试]使用主机libthread_db 库“/lib64/libthread_db.so.1”。

断点1,主()在main.cpp中:51

51如果(totalRead => actualSize!){

(GDB)p totalRead

$ 1 = 9000032

(gdb)p actualSize

$ 2 = 9000032

所以基本上你的程序对我来说是完美无缺的。也许你的文件系统有问题,或者与此无关。

我使用ext4作为文件系统。

ll从我正在阅读的文件中报告此尺寸9000032 abr 29 16:10 WebDev.pdf,因此您可以看到它实际上是正确的。我的页面尺寸为

$ getconf PAGESIZE 
4096 
+0

谢谢你的回答。我应该在问题中指出更多。 我无法获得TOCTOU问题。我正在阅读只读的文件,无法删除。请阅读更新后的问题,如果您有更新的答案,我将非常感激。 –