Question

Je travaille sur un code qui, entre autres, doit enregistrer un fichier rempli de zéro. Il peut s'attendre à créer un fichier de 10 Mo à un blanc uniforme de 1 Go.

Il doit être similaire à cette commande UNIX:

dd if=/dev/zero of=my_image.dsk count=20480

Je pourrais faire ce seul travail avec de petites tailles:

int totalSize = 1024*1024;
char buf[totalSize];
strcpy(buf,"");

NSData *theData = [NSData dataWithBytes:buf length:sizeof(buf)];

//NSLog(@"%@", theData);
NSLog(@"%lu", sizeof(buf));

[theData writeToFile:@"/Users/foo/Desktop/my_image.dsk" atomically:YES];

Mais si j'essaye une valeur plus grande (1024 * 1024 * 10, par exemple), il se bloque. Alors j'ai essayé:

NSFileManager *ddd = [[NSFileManager alloc ] init];
[ddd createFileAtPath:@"/Users/foo/Desktop/my_image.dsk" contents:[NSData data] attributes:nil];

Il crée un fichier vide, mais n'est pas bon car la taille du fichier est nul. Il ne devrait pas être nul.

J'ai passé des heures à essayer de trouver une réponse sans succès. Je veux le faire dans OBJ-C, mais C est également une option avant de devenir fou.

S'il vous plaît, quelqu'un me donne de la lumière!

Merci d'avance!

-- Éditer --

Merci à tous, mais encore une chose: est-il possible d'écrire sans tout allouer sur la mémoire?

Était-ce utile?

La solution

Vous pouvez utiliser dd. Cela vous permettra d'écrire, par exemple, 10 Go sans vous soucier de la mémoire ou de l'espace d'adressage.

NSTask *task = [NSTask new];
long size = ...; // Note! dd multiplies this by 512 by default
NSString *path = ...;
[task setLaunchPath:@"/bin/dd"];
[task setArguments:[NSArray arrayWithObjects:@"dd", @"if=/dev/zero",
    [NSString stringWithFormat:@"of=%s", [path fileSystemRepresentation]],
    [NSString stringWithFormat:@"count=%ld", size],
    nil]];
[task launch];
[task waitUntilExit];
if ([task terminationStatus] != 0) {
    // an error occurred...
}
[task release];

Un avantage est que les utilisateurs sophistiqués peuvent tuer dd Si quelque chose ne va pas.

À propos du sable: Mon soupçon est que cela fonctionnera bien même dans un bac à sable, mais je serais curieux de savoir avec certitude. Selon la documentation (lien), un sous-processus "hérite simplement du bac à sable du processus qui l'a créé". C'est exactement comme ça que vous vous attendez à ce qu'il fonctionne sur Unix.

Vous pouvez être sûr que dd Restera car Apple affirme que OS X est conforme à SUSV3.

Autres conseils

Ceci est relativement simple dans l'API POSIX:

int f = open("filename", O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
if (f < 0) {
    perror("open filename");
    exit(1);
}

char empty = 0;

pwrite(f, &empty, sizeof(char), <offset into the file>);

Le décalage est spécifié à l'aide d'un entier de type off_t, qui pourrait ne pas être suffisamment grand pour vos besoins spécifiques. Vérifiez la documentation de votre API système pour découvrir les interfaces de fichier 64 bits si elle n'est pas assez grande.

La meilleure partie de cette approche est qu'elle ne prend que quelques octets de la mémoire du programme - vous n'allouez pas 10 gigaoctets de rien pour écrire votre fichier.

Une autre approche encore plus simple consiste à utiliser le truncate(2) appel système. Toutes les plates-formes ne prennent pas en charge l'extension du fichier avec truncate(2), mais pour ceux qui le font, c'est un appel.

Essayez ce code:

int totalSize = 1024*1024;
// don't allocate on the stack
char *buf = calloc(totalSize, sizeof(char));

NSData *theData = [NSData dataWithBytesNoCopy:buf length:totalSize];

//NSLog(@"%@", theData);
NSLog(@"%lu", totalSize);

[theData writeToFile:@"/Users/foo/Desktop/my_image.dsk" atomically:YES];

Vous pouvez également essayer ceci, moins d'un porc de mémoire, et cela fonctionne avec un fichier de 1 Go.

void writeBlankBytes(FILE *file, size_t numKB)
{
    static char *oneKBZero = NULL;

    if (oneKBZero == NULL)
    {
        oneKBZero = calloc(1024, sizeof(char));
    }

    for (int i = 0; i < numKB; i++) {
        fwrite(oneKBZero, 1, 1024, file);
    }
}

Merci tout le monde. Je suis venu à une solution. Il s'agit essentiellement d'un croquis du code que je suis sur le point de mettre dans une application de cacao.

Fonctionne bien et je pense que je n'ai besoin que de précautions avec la variable de taille et ce sera suffisant.

long size = 2000*500;

NSString *path = [[NSString alloc] initWithFormat: @"/Users/foo/Desktop/testeFile.dsk"];

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/dd"];
[task setArguments:[NSArray arrayWithObjects:
                    @"if=/dev/zero",
                    [NSString stringWithFormat:@"of=%s", [path fileSystemRepresentation]],
                    [NSString stringWithFormat:@"count=%ld", size],
                    nil]];
NSLog(@"%@",[task arguments]);
[task launch];

//[task waitUntilExit]; //The app would stuck here.. better use the loop

int cont = 0;
while ([task isRunning]) {
    cont++;
    if(cont%100==0) NSLog(@". %d", cont);
}

if ([task terminationStatus] != 0) {
    NSLog(@"an error occurred...");
}
[task release];
[path release];

NSLog(@"Done!");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top