2012-01-16 3 views
2

다른 것들 중에서 0으로 채워진 파일을 저장해야하는 코드 작업 중입니다. 10MB에서 1GB 공백까지 파일을 생성 할 것으로 예상됩니다.Objective-C에 빈 파일 저장

이 유닉스 명령과 유사합니다

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

내가 작은 크기의이 하나의 작업을 할 수있는 :

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

을하지만 더 큰 값을 시도하는 경우 (1024 * 1024 * 10 예를 들어), 충돌합니다. 그래서 나는 시도 :

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

그것은 빈 파일을 만들지 만 파일 크기가 0이기 때문에 좋지 않다. 0이 아니어야합니다.

나는 성공하지 못한 채 몇 시간을 보냈다. Obj-C에서이 작업을 수행하려고하지만, C가 옵션이되기 전에야 견해를 나타냅니다.

제발 누군가 제게 빛을주세요!

미리 감사드립니다.

- 편집 -

모두에게 감사하지만, 한 가지 더 : 메모리에있는 모든 할당하지 않고이 가능를 작성하려면?

+0

스택에 할당하기 때문에 충돌이 발생합니다. 스택에 제한된 메모리가 있습니다. 스택에 1 MB를 그대로 할당하려고하면 malloc 및 memset 호출을 사용하는 것이 좋습니다. –

+0

@ RichardJ.RossIII : 일반적으로'malloc'과'memset'은 사용하지 말고'calloc'을 대신 사용하십시오. 그렇게 많은 메모리를 절약 할 수 있습니다. –

+0

@DietrichEpp 정말요? 다른 방법을 들었습니다. 그리고 memset이 calloc 호출보다 낫습니다. 왜냐하면 더 많이 인라인되어 있기 때문입니까? 내가들은 바로는 나중에 어느쪽으로도 말할 수 없다. –

답변

3

dd을 사용할 수 있습니다. 이렇게하면 메모리 나 주소 공간을 걱정하지 않고 10GB로 쓸 수 있습니다.

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

어떤 점이 잘못되면 정교한 사용자가 dd을 죽일 수 있다는 이점이 있습니다.

샌드 박스 정보 : 의심의 여지가이 샌드 박스에서 잘 작동하지만, 나는 확실히 알고 싶습니다.문서 (link)에 따르면, 하위 프로세스는 "단순히 프로세스를 만든 프로세스의 샌드 박스를 상속합니다." 이것이 유닉스에서 어떻게 작동하는지 정확히 알 수 있습니다.

Apple이 OS X가 SUSv3을 준수한다고 주장하므로 dd이 계속 붙을 수 있습니다.

+0

흥미 롭 .. 기본적으로 오류가 발생하면 "kill"조치를 구현하는 것이 너무 많은 작업이라고 생각하십니까? – Apollo

+0

오류 :'프로그램 수신 신호 : "SIGABRT"및 로그 :'2012-01-16 01 : 56 : 05.977 파일 핸들러 [2448 : 903] *** 캐치되지 않은 예외로 인해 앱 종료 'NSInvalidArgumentException' 이유 : 'launch path not accessible' *** 처음 던질 때 호출 스택 : – Apollo

+0

@GiancarloMariot : 작성한대로'dd '가 종료되면 오류가 감지되므로'dd'를 죽일 필요가 없습니다. 'dd' 프로그램은 정상적으로 에러가 발생하면 즉시 종료됩니다. –

1

이 코드보십시오 : 당신은 또한 메모리 돼지의 덜이, 시도 할 수

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

을, 그리고 1 기가 바이트 파일과 함께 작동합니다.

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

'totalSize'가 10GB에 접근 할 때이 접근 방식은 어떻게됩니까? – aroth

+0

그런데 경건하지 않은 이유로 10GB가 넘는 RAM이없는 한, 너는 망했다. –

+0

@ RichardJ.RossIII :'malloc' /'memset' 대신에'calloc' (항상 *해야 함 *)을 사용했다면 RAM이 많지 않더라도 64 비트 컴퓨터에서도 문제가 없습니다. –

4

이것은 POSIX API의 비교적 간단하다 :

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

귀하의 특정 요구에 충분하지 않을 수도 있습니다 유형 off_t의 정수를 사용하여 지정된 오프셋. 64 비트 파일 인터페이스가 충분히 크지 않은 경우 시스템 API 문서를 확인하여 64 비트 파일 인터페이스를 찾습니다.

이 접근법의 가장 좋은 점은 파일 쓰기에 10 기가 바이트를 할당하지 않고 단지 몇 바이트의 프로그램 메모리 만 필요하다는 것입니다.

더 간단한 방법은 truncate(2) 시스템 호출을 사용하는 것입니다. 모든 플랫폼이 truncate(2)으로 파일 확장을 지원하는 것은 아니지만, 수행하는 경우에는 하나의 호출입니다.

+0

예. 때때로 오래된 방법이 가장 잘 작동합니다. – aroth

+1

모든 응용 프로그램에서 스파 스 파일을 만들지는 않습니다. 권한을 0666으로 변경하고 사용자가 자신의'umask'를 설정할 수 있습니다. –

+0

위대한, 모든 것을 메모리에 할당하지 않는 무언가를 찾고 있었기 때문에 이것은 좋은 시작입니다. 그러나이 오프셋으로 나를 잃어 버렸습니다. xD – Apollo

1

감사합니다. 나는 해결책을 찾았다. 이것은 기본적으로 내가 코코아 응용 프로그램에 넣을 코드의 스케치입니다.

잘 작동하고 크기 변수에 몇 가지 예방 조치 만 있으면 충분하다고 생각합니다.

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!"); 
+0

이것은 'dd'가 사용 가능하고 특히/bin/dd에 위치한다는 것에주의하십시오. 두 요구 사항 중 하나라도 충족되지 않으면 프로그램이 실패합니다. 아마 몇 년 동안이 방법이 효과가 있지만, 이러한 의존성이없는 간단한 방법을 사용할 수 있다고 생각합니다. – sarnold

+0

@sarnold 당신이 말한대로 좋은 방법을 찾을 수 있었으면 좋겠지 만, 저장하기 전에 모두 파일을 메모리에 던지면 사용자가 1GB 파일을 요청하면 응용 프로그램이 충돌하거나 적어도 코끼리가됩니다. 간단한 해결책을 찾기 위해 어디에서나 찾아 왔습니다. 여기에서 볼 수있는 모든 해결책을 볼 수 있습니다. = ( 새로운 제안이 있으시면 좋을 것입니다. =) – Apollo

+0

[Dietrich 's 대답] (http://stackoverflow.com/a/8874811/377270) 좋다; 새로운 프로세스를 시작하는 것에 대한'NPROC'' setrlimit (2)'제약 조건은 상당히 낮습니다. 그리고 그가 제공 한 샌드 박스 가이드에 대한 링크는 여러분에게 _user_보다는 어플리케이션 작성자가 책임이 있음을 나타냅니다 샌드 박스를 제공하기 때문에 응용 프로그램에 실제 장애가되지는 않습니다. 내 제안 _does_ 원하는 스파크 파일을 만들 수 있으며 다른 API 수준에서 작동해야합니다. – sarnold