C++ tellg() 函数给出错误的文件大小?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22984956/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
tellg() function give wrong size of file?
提问by Elior
I did a sample project to read a file into a buffer. When I use the tellg() function it gives me a larger value than the read function is actually read from the file. I think that there is a bug.
我做了一个示例项目来将文件读入缓冲区。当我使用 tellg() 函数时,它给了我一个比从文件中实际读取的 read 函数更大的值。我认为有一个错误。
here is my code:
这是我的代码:
EDIT:
编辑:
void read_file (const char* name, int *size , char*& buffer)
{
ifstream file;
file.open(name,ios::in|ios::binary);
*size = 0;
if (file.is_open())
{
// get length of file
file.seekg(0,std::ios_base::end);
int length = *size = file.tellg();
file.seekg(0,std::ios_base::beg);
// allocate buffer in size of file
buffer = new char[length];
// read
file.read(buffer,length);
cout << file.gcount() << endl;
}
file.close();
}
main:
主要的:
void main()
{
int size = 0;
char* buffer = NULL;
read_file("File.txt",&size,buffer);
for (int i = 0; i < size; i++)
cout << buffer[i];
cout << endl;
}
回答by James Kanze
tellg
does not report the size of the file, nor the offset
from the beginning in bytes. It reports a token value which can
later be used to seek to the same place, and nothing more.
(It's not even guaranteed that you can convert the type to an
integral type.)
tellg
不报告文件的大小,也不报告从字节开始的偏移量。它报告一个令牌值,以后可以用来寻找同一个地方,仅此而已。(甚至不能保证您可以将类型转换为整数类型。)
At least according to the language specification: in practice,
on Unix systems, the value returned will be the offset in bytes
from the beginning of the file, and under Windows, it will be
the offset from the beginning of the file for files opened in
binary mode. For Windows (and most non-Unix systems), in text
mode, there is no direct and immediate mapping between what
tellg
returns and the number of bytes you must read to get to
that position. Under Windows, all you can really count on is
that the value will be no less than the number of bytes you have
to read (and in most real cases, won't be too much greater,
although it can be up to two times more).
至少根据语言规范:在实践中,在 Unix 系统上,返回的值将是从文件开头的偏移量(以字节为单位),而在 Windows 下,它将是打开的文件从文件开头的偏移量二进制模式。对于 Windows(和大多数非 Unix 系统),在文本模式下,tellg
返回的内容与到达该位置必须读取的字节数之间没有直接和直接的映射
。在 Windows 下,您真正可以指望的是该值将不小于您必须读取的字节数(并且在大多数实际情况下,不会太大,尽管它最多可以多两倍)。
If it is important to know exactly how many bytes you can read, the only way of reliably doing so is by reading. You should be able to do this with something like:
如果确切知道您可以读取多少字节很重要,那么可靠地这样做的唯一方法就是读取。您应该可以使用以下方法执行此操作:
#include <limits>
file.ignore( std::numeric_limits<std::streamsize>::max() );
std::streamsize length = file.gcount();
file.clear(); // Since ignore will have set eof.
file.seekg( 0, std::ios_base::beg );
Finally, two other remarks concerning your code:
最后,关于您的代码的另外两个评论:
First, the line:
首先,线路:
*buffer = new char[length];
shouldn't compile: you have declared buffer
to be a char*
,
so *buffer
has type char
, and is not a pointer. Given what
you seem to be doing, you probably want to declare buffer
as
a char**
. But a much better solution would be to declare it
as a std::vector<char>&
or a std::string&
. (That way, you
don't have to return the size as well, and you won't leak memory
if there is an exception.)
不应编译:您已声明buffer
为 a char*
,因此*buffer
具有 type char
,并且不是指针。鉴于您似乎在做什么,您可能想要声明buffer
为char**
. 但是更好的解决方案是将其声明为 astd::vector<char>&
或 a std::string&
。(这样,您也不必返回大小,并且在出现异常时不会泄漏内存。)
Second, the loop condition at the end is wrong. If you really want to read one character at a time,
其次,最后的循环条件是错误的。如果你真的想一次读一个字符,
while ( file.get( buffer[i] ) ) {
++ i;
}
should do the trick. A better solution would probably be to read blocks of data:
应该做的伎俩。更好的解决方案可能是读取数据块:
while ( file.read( buffer + i, N ) || file.gcount() != 0 ) {
i += file.gcount();
}
or even:
甚至:
file.read( buffer, size );
size = file.gcount();
EDIT: I just noticed a third error: if you fail to open the
file, you don't tell the caller. At the very least, you should
set the size
to 0 (but some sort of more precise error
handling is probably better).
编辑:我刚刚注意到第三个错误:如果您无法打开文件,请不要告诉来电者。至少,您应该将 设置size
为 0(但某种更精确的错误处理可能更好)。
回答by fen
In C++17 there are std::filesystem
file_size
methods and functions, so that can streamline the whole task.
在 C++17 中有std::filesystem
file_size
方法和函数,所以可以简化整个任务。
- std::filesystem::file_size - cppreference.com
- std::filesystem::directory_entry::file_size - cppreference.com
- std::filesystem::file_size - cppreference.com
- std::filesystem::directory_entry::file_size - cppreference.com
With those functions/methods there's a chance not to open a file, but read cached data (especially with the std::filesystem::directory_entry::file_size
method)
使用这些函数/方法,有机会不打开文件,而是读取缓存数据(尤其是使用该std::filesystem::directory_entry::file_size
方法)
Those functions also require only directory read permissions and not file read permission (as tellg()
does)
这些函数也只需要目录读取权限,而不需要文件读取权限(也是tellg()
如此)
回答by Arks
void read_file (int *size, char* name,char* buffer)
*buffer = new char[length];
These lines do look like a bug: you create an char array and save to buffer[0] char. Then you read a file to buffer, which is still uninitialized.
这些行确实看起来像一个错误:您创建了一个字符数组并保存到缓冲区 [0] 字符。然后您将一个文件读取到缓冲区,该文件仍未初始化。
You need to pass buffer
by pointer:
您需要buffer
通过指针传递:
void read_file (int *size, char* name,char** buffer)
*buffer = new char[length];
Or by reference, which is the c++ way and is less error prone:
或者通过引用,这是 c++ 方式并且不太容易出错:
void read_file (int *size, char* name,char*& buffer)
buffer = new char[length];
...
回答by Dr. Debasish Jana
fseek(fptr, 0L, SEEK_END);
filesz = ftell(fptr);
will do the file if file opened through fopen
如果文件通过 fopen 打开,将执行该文件
using ifstream,
使用 ifstream,
in.seekg(0,ifstream::end);
dilesz = in.tellg();
would do similar
会做类似的