Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 13:00 Der er 25 kommentarer og
1 løsning

C++ og store filer (64 bit adress)

Hejsa,

jeg er igang med at lave en editor, der skal kunne håndtere op til 18 exabyte store filer. I forbindelse med dette er jeg løbet ind i et lille problem :)

---------- Kode snip ----------------

File::File(const std::string *path, const int perm)
{
    this->file = new std::fstream(path->c_str(), perm);
    this->path = path;
}

void File::read(char *buffer, const size_t size)
{
    if (true == this->file->is_open())
    {
        this->file->read(buffer, size);
    }
    else
    {
        throw new System::Exception(); // change exception
    }
}

File::~File()
{
    this->file->close();
    delete this->file;
}

---------- /Kode snip ----------------

Jeg får følgende warning:
File.cpp(13) : warning C4267: 'argument' : conversion from 'size_t' to 'std::streamsize', possible loss of data

size_t er defineret til at være 64 bit, og det vil jo så sige at 'std::streamsize' må være 'mindre'... Dette er jo ikke skide godt, når jeg skal bruge 64 bit addressering.

Er der nogen, der kender en løsning på dette problem?
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 13:02 #1
Det samme gælder for:

void File::readBlock(size_t position, char *buffer, std::streamsize size)
{
    if (true == this->file->is_open())
    {
        this->file->seekg(position, std::ios_base::beg);
        this->file->read(buffer, size);
    }
    else
    {
        throw new System::Exception();
    }
}
Avatar billede arne_v Ekspert
19. september 2004 - 13:14 #2
Hvilken platform og settings ? (meget ofte er size_t også kun 32 bit)

Hvorfor kan du ikke læse ind i klumper ? (umiddelbart vil jeg vurdere at
overheadet ved et kald af read per 2 eller 4 GB data må være minimalt)
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 13:24 #3
Det er på en Windows NT platform (ie. 2000/XP), som benytter 64 bit addressering på OS, hvilket vil sige at filer ikke længere har en maksimal størrelse på 18 exabyte.

Begrænsningen består i at man skal bruge en integer til at holde styr på hvor man er i filen.
Tidligere OS versioner brugte en 32 bit signed integer => max (2^32)/2 = 2147483648 bytes
Så fandt man ud af at man kunne droppe sign => max 2^32 = 4294967294 bytes
Og nu 64 bit unsigned adressering => max 2^64 = 18 millioner gigabyte (18 exabyte)
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 13:28 #4
Ups... lige en fejl i det første post.. problemet er ikke hvor store klumper jeg kan læse, men fil pointeren:
f.eks. i:
this->file->seekg(position, std::ios_base::beg);
Jeg kan kun positionere fil pointeren 2^32 byte fra starten.. og altså ikke læse mere end 4 GB, selvom det burde være muligt :/
Avatar billede arne_v Ekspert
19. september 2004 - 13:32 #5
NTFS tillader volumes op til 16 EB (som er 16 milliarder GB ikke 18 millioner GB).

Windows 2000 har dog en limit på 128 TB (jeg ved ikke med XP pg 2003).
Avatar billede arne_v Ekspert
19. september 2004 - 13:35 #6
Men du siger at dit problem er at off_type er 32 bit ?
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 13:39 #7
jep.. fstream kan åbenbart kun klare 4 GB.. men der må være en 64 bit ækvivalent. Med hensyn til max filstørrelse på de pågældende system, så afhænger det af hvilken page size partitionen har.
Avatar billede arne_v Ekspert
19. september 2004 - 13:42 #8
Jeg testede lige lidt.

Med VC++ 7.1 så er off_type som er argumentet til seekg med 2 argumenter 32 bit,
men pos_type som er argumentet til seekg med 1 argument er 64 bit.

Kan du ikke bare bruge 1 argument varianten ?
Avatar billede arne_v Ekspert
19. september 2004 - 13:47 #9
Ellers kan du gå ned i Win32 API hvor SetFilePointer tager 2 32 bit argumenter med
henholdsvis low og high.
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 14:22 #10
Hmm.. seekg med et argument er også 32 bit i VC++ 7.2.
Win32 API kald duer desværre ikke, da det skal være cross platform...

Måske kan det lade sig gøre med et lille hack, hvor jeg repositionerer pointeren i incrementer på 4GB..
Altså f.eks. hvis jeg skal læse inde i filen ved 8 GB og 1 MB:
this->file->seekg(4294967296, std::ios_base::beg); // jmp first 4 GB
this->file->seekg(4294967296, std::ios_base::cur); // jmp second 4 GB
this->file->seekg(1024, std::ios_base::cur); // jmp target
// start reading
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 14:33 #11
void File::readBlock(size_t position, char *buffer, std::streamsize size)
{
    if (true == this->file->is_open())
    {
        // hack begin
        this->file->seekg(0, std::ios_base::beg);
        while (position > 4294967295)
        {
            this->file->seekg(4294967295, std::ios_base::cur);
            position = position -4294967295;
        }
        this->file->seekg((unsigned __int32)position, std::ios_base::cur);
        // hack end
        this->file->read(buffer, size);
    }
    else
    {
        throw new System::Exception();
    }
}
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 14:46 #12
Ved ikke om det virker, har nemlig ikke så store filer.. nogen, der kan prøve det af?
Avatar billede arne_v Ekspert
19. september 2004 - 14:48 #13
Jeg har kkigget lidt nærmere på pos_type. Den indeholder altså en 64 bit fpos_t, men
den indeholder rogså en 32 bit streamoff.

:-)
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 14:51 #14
Hmmm.. cool... har du et link?
Avatar billede arne_v Ekspert
19. september 2004 - 14:52 #15
Kig i iosfwd !
Avatar billede arne_v Ekspert
19. september 2004 - 14:53 #16
Jeg har lige checket med multiple seekg metoden.

Det virker ikke hos mig.
Avatar billede arne_v Ekspert
19. september 2004 - 14:55 #17
Men hvis du nu bruger C og ikke C++, så ser det ud som om at fsetpos bruger
en fpos_t altså 64 bit.
Avatar billede arne_v Ekspert
19. september 2004 - 15:04 #18
FILE *fp=fopen("big.dat","rb");
  ...
  fsetpos(fp,&offset);
  fread(buf,sizeof(buf),1,fp);

virker med 64 bit offste hos mig (og VC++ 7.1)
Avatar billede nemezis_aalborg Nybegynder
19. september 2004 - 15:09 #19
he he...
det var fordi jeg kiggede på fstream og du på stdio.h.. prøver lige.. tak
Avatar billede arne_v Ekspert
19. september 2004 - 15:22 #20
Nå men det var da også mest naturligt at bruge fstream i C++.

Men når fstream ikke rigtigt vil og man opdager at fpos_t (som er C)
ser lovende ud så ...
Avatar billede arne_v Ekspert
19. september 2004 - 15:27 #21
Du er vel klar over at koden aldrig vil blive ægte cross platform, da
du ikke kan regne med support for så store filer.
Avatar billede arne_v Ekspert
19. september 2004 - 21:06 #22
og et svar
Avatar billede nemezis_aalborg Nybegynder
20. september 2004 - 13:53 #23
[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_fgetpos.asp]
The fgetpos function gets the current value of the stream argument's file-position indicator and stores it in the object pointed to by pos. The fsetpos function can later use information stored in pos to reset the stream argument's pointer to its position at the time fgetpos was called. The pos value is stored in an internal format and is intended for use only by fgetpos and fsetpos.

> fgetpos virker altså ikke. Hvis jeg prøver halter .NET bare og siger at jeg skal kontakte programmets support team :)

Løsningen var at bruge _lseeki64:

__int64 _lseeki64(
  int fd,
  __int64 offset,
  int origin
);
Avatar billede arne_v Ekspert
20. september 2004 - 13:58 #25
Det virkede fint med fsetpos hos mig. Jeg kan godt sende dig eksemplet.
Avatar billede arne_v Ekspert
20. september 2004 - 13:59 #26
Og jeg havde set *64, men du sagde jo at du ville have en standard løsning.

Der er jo ikke meget pointe i at forkaste en Win32 API funktion der kan bruges
i enhver Windows compiler for en MS VC++ specifik funktion.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester