Сообщение Re[2]: std::ifstream, MSVC 2012, бага? от 17.02.2015 11:45
Изменено 17.02.2015 11:46 nen777w
PM>Теоретически, использование stream.tellg() — это непереносимый способ узнать размер файла. Так как tellg() возвращает лишь некое положение в потоке данных, которое в дальнейшем может быть использовано чтобы вернуться к этому положению.
PM>Единственный способ узнать размер потока в С++ используя IOStreams — это прочитать весь поток до конца, проигнорировав все данные и потом узнать кол-во прочитанных байт:
[skip]
PM>Источник: http://stackoverflow.com/a/22986486/1355844
Спасибо.
PM>Самый надежный вариант — использовать API целевой платформы, ну или boost::filesystem для большинства распространенных платформ.
Ладно. Но суть не в размере файла.
Суть в этом:
Уже давайте по чесноку что бы вообще, (хотя ИМХО оно не должно от этого зависить), приложение 64-битное.
Пошел копать...
Стрим открывается, потом ему делают:
Так вот fseek() не вернул 0.
Копаем в fseek() последнее что там делают куда без дизассемблирование не докопаться это в long __cdecl _lseek_nolock()
GetLastError() вернул 87
Что означает:
SetFilePointer()
Идём дальше:
Копаем:
Опа... а в конце то все дело теперь делает: __int64 __cdecl _lseeki64_nolock()
И уже знакомый код, только теперь он выглядит вот так и всю работу теперь делает SetFilePointerEx:
newpos.QuadPart будет содержать то что и ожидалось 10737418240 т.е. длинну нашего 10Gb файла.
Ну вот так вот... у меня пока всё.
Но судя по всему звать нужно было SetFilePointerEx() т.к. SetFilePointer() оперирует с LONG а вот SetFilePointerEx() LARGE_INTEGER
Бага?
PM>Единственный способ узнать размер потока в С++ используя IOStreams — это прочитать весь поток до конца, проигнорировав все данные и потом узнать кол-во прочитанных байт:
[skip]
PM>Источник: http://stackoverflow.com/a/22986486/1355844
Спасибо.
PM>Самый надежный вариант — использовать API целевой платформы, ну или boost::filesystem для большинства распространенных платформ.
Ладно. Но суть не в размере файла.
Суть в этом:
std::ifstream in(path, std::ifstream::ate|std::ifstream::binary);
if(!in.good()) {
//WTF? для файлов больше 10Gb
}
Уже давайте по чесноку что бы вообще, (хотя ИМХО оно не должно от этого зависить), приложение 64-битное.
Пошел копать...
Стрим открывается, потом ему делают:
if (!atendflag || fseek(fp, 0, SEEK_END) == 0)
return (fp); // no need to seek to end, or seek succeeded
fclose(fp); // can't position at end
return (0);
Так вот fseek() не вернул 0.
Копаем в fseek() последнее что там делают куда без дизассемблирование не докопаться это в long __cdecl _lseek_nolock()
/*ГДЕ: osHandle - какой то 64 битный дискриптор равен: 0x20 (думаю валидный)
pos - 0
mthd - 2
*/
if ((osHandle = (HANDLE)_get_osfhandle(fh)) == (HANDLE)-1)
{
errno = EBADF;
_ASSERTE(("Invalid file descriptor",0));
return -1;
}
if ((newpos = SetFilePointer(osHandle, pos, NULL, mthd)) == -1)
dosretval = GetLastError(); <<-- UUUUPS....
else
dosretval = 0;
GetLastError() вернул 87
Что означает:
ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.
SetFilePointer()
Идём дальше:
std::ifstream in(path, /*std::ifstream::ate|*/std::ifstream::binary);
if(!in.good()) {
return 0;
}
in.seekg(0, std::ifstream::end);
//и еще раз
if(!in.good()) {
return 0;
}
все ок!
Копаем:
Опа... а в конце то все дело теперь делает: __int64 __cdecl _lseeki64_nolock()
И уже знакомый код, только теперь он выглядит вот так и всю работу теперь делает SetFilePointerEx:
Параметры всё те же, только заиспользовали LARGE_INTEGER newpos;
if ((osHandle = (HANDLE)_get_osfhandle(fh)) == (HANDLE)-1)
{
errno = EBADF;
_ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
return( -1i64 );
}
if (!SetFilePointerEx( osHandle,
*(PLARGE_INTEGER)&pos,
&newpos,
mthd) )
{
_dosmaperr( GetLastError() );
return( -1i64 );
}
newpos.QuadPart будет содержать то что и ожидалось 10737418240 т.е. длинну нашего 10Gb файла.
Ну вот так вот... у меня пока всё.
Но судя по всему звать нужно было SetFilePointerEx() т.к. SetFilePointer() оперирует с LONG а вот SetFilePointerEx() LARGE_INTEGER
Бага?
PM>Теоретически, использование stream.tellg() — это непереносимый способ узнать размер файла. Так как tellg() возвращает лишь некое положение в потоке данных, которое в дальнейшем может быть использовано чтобы вернуться к этому положению.
PM>Единственный способ узнать размер потока в С++ используя IOStreams — это прочитать весь поток до конца, проигнорировав все данные и потом узнать кол-во прочитанных байт:
[skip]
PM>Источник: http://stackoverflow.com/a/22986486/1355844
Спасибо.
PM>Самый надежный вариант — использовать API целевой платформы, ну или boost::filesystem для большинства распространенных платформ.
Ладно. Но суть не в том что бы узнать размер файла.
Суть в этом:
Уже давайте по чесноку что бы вообще, (хотя ИМХО оно не должно от этого зависить), приложение 64-битное.
Пошел копать...
Стрим открывается, потом ему делают:
Так вот fseek() не вернул 0.
Копаем в fseek() последнее что там делают куда без дизассемблирование не докопаться это в long __cdecl _lseek_nolock()
GetLastError() вернул 87
Что означает:
SetFilePointer()
Идём дальше:
Копаем:
Опа... а в конце то все дело теперь делает: __int64 __cdecl _lseeki64_nolock()
И уже знакомый код, только теперь он выглядит вот так и всю работу теперь делает SetFilePointerEx:
newpos.QuadPart будет содержать то что и ожидалось 10737418240 т.е. длинну нашего 10Gb файла.
Ну вот так вот... у меня пока всё.
Но судя по всему звать нужно было SetFilePointerEx() т.к. SetFilePointer() оперирует с LONG а вот SetFilePointerEx() LARGE_INTEGER
Бага?
PM>Единственный способ узнать размер потока в С++ используя IOStreams — это прочитать весь поток до конца, проигнорировав все данные и потом узнать кол-во прочитанных байт:
[skip]
PM>Источник: http://stackoverflow.com/a/22986486/1355844
Спасибо.
PM>Самый надежный вариант — использовать API целевой платформы, ну или boost::filesystem для большинства распространенных платформ.
Ладно. Но суть не в том что бы узнать размер файла.
Суть в этом:
std::ifstream in(path, std::ifstream::ate|std::ifstream::binary);
if(!in.good()) {
//WTF? для файлов больше 10Gb
}
Уже давайте по чесноку что бы вообще, (хотя ИМХО оно не должно от этого зависить), приложение 64-битное.
Пошел копать...
Стрим открывается, потом ему делают:
if (!atendflag || fseek(fp, 0, SEEK_END) == 0)
return (fp); // no need to seek to end, or seek succeeded
fclose(fp); // can't position at end
return (0);
Так вот fseek() не вернул 0.
Копаем в fseek() последнее что там делают куда без дизассемблирование не докопаться это в long __cdecl _lseek_nolock()
/*ГДЕ: osHandle - какой то 64 битный дискриптор равен: 0x20 (думаю валидный)
pos - 0
mthd - 2
*/
if ((osHandle = (HANDLE)_get_osfhandle(fh)) == (HANDLE)-1)
{
errno = EBADF;
_ASSERTE(("Invalid file descriptor",0));
return -1;
}
if ((newpos = SetFilePointer(osHandle, pos, NULL, mthd)) == -1)
dosretval = GetLastError(); <<-- UUUUPS....
else
dosretval = 0;
GetLastError() вернул 87
Что означает:
ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.
SetFilePointer()
Идём дальше:
std::ifstream in(path, /*std::ifstream::ate|*/std::ifstream::binary);
if(!in.good()) {
return 0;
}
in.seekg(0, std::ifstream::end);
//и еще раз
if(!in.good()) {
return 0;
}
все ок!
Копаем:
Опа... а в конце то все дело теперь делает: __int64 __cdecl _lseeki64_nolock()
И уже знакомый код, только теперь он выглядит вот так и всю работу теперь делает SetFilePointerEx:
Параметры всё те же, только заиспользовали LARGE_INTEGER newpos;
if ((osHandle = (HANDLE)_get_osfhandle(fh)) == (HANDLE)-1)
{
errno = EBADF;
_ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
return( -1i64 );
}
if (!SetFilePointerEx( osHandle,
*(PLARGE_INTEGER)&pos,
&newpos,
mthd) )
{
_dosmaperr( GetLastError() );
return( -1i64 );
}
newpos.QuadPart будет содержать то что и ожидалось 10737418240 т.е. длинну нашего 10Gb файла.
Ну вот так вот... у меня пока всё.
Но судя по всему звать нужно было SetFilePointerEx() т.к. SetFilePointer() оперирует с LONG а вот SetFilePointerEx() LARGE_INTEGER
Бага?