Domanda

Sto lavorando su un codice che, tra le altre cose, deve salvare un file pieno di zero. Può aspettarsi di creare un file da 10 MB a anche 1 GB.

Deve essere simile a questo comando UNIX:

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

Potrei fare questo lavoro con piccole dimensioni:

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];

Ma se provo un valore maggiore (1024*1024*10, ad esempio), si blocca. Quindi ho provato:

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

Crea un file vuoto, ma non è buono perché la dimensione del file è zero. Non dovrebbe essere zero.

Ho trascorso ore a cercare una risposta senza successo. Voglio farlo in OBJ-C, ma C è anche un'opzione prima di impazzire.

Per favore, qualcuno dà a me un po 'di luce!

Grazie in anticipo!

-- Modificare --

Grazie a tutti, ma un'altra cosa: è possibile scrivere senza assegnare tutto in memoria?

È stato utile?

Soluzione

Puoi usare dd. Questo ti permetterà di scrivere, ad es. 10 GB senza preoccuparti della memoria o dello spazio degli indirizzi.

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 vantaggio è che gli utenti sofisticati possono uccidere dd Se qualcosa va storto.

Informazioni sul sandboxing: Il mio sospetto è che questo funzionerà bene anche in una sandbox, ma sarei curioso di saperlo con certezza. Secondo la documentazione (collegamento), un sottoprocesso "eredita semplicemente la sandbox del processo che l'ha creata". Questo è esattamente il modo in cui ti aspetteresti che funzioni su Unix.

Puoi essere sicuro che questo dd Rimarrà in giro da quando Apple afferma che OS X si conformerà a SUSV3.

Altri suggerimenti

Questo è relativamente semplice nell'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>);

L'offset è specificato utilizzando un numero intero di tipo off_t, che potrebbe non essere abbastanza grande per le tue esigenze specifiche. Controlla la documentazione API di sistema per scoprire le interfacce file a 64 bit se non è abbastanza grande.

La parte migliore di questo approccio è che ci vogliono solo pochi byte di memoria del programma: non stai assegnando 10 gigabyte di nulla per scrivere il tuo file.

Un altro approccio ancora più semplice è usare il truncate(2) Chiamata di sistema. Non tutte le piattaforme supportano l'estensione del file con truncate(2), ma per quelli che lo fanno una chiamata.

Prova questo codice:

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];

Potresti anche provare questo, meno di un maiale di memoria e funziona con un file da 1 GB.

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);
    }
}

Grazie a tutti. Sono arrivato a una soluzione. Questo è fondamentalmente uno schizzo del codice che sto per inserire un'app di cacao.

Funziona bene e penso di aver bisogno solo di alcune precauzioni con la variabile dimensionale e sarà sufficiente.

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!");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top