Create and write to a file incrementally with NSFileHandle

169 views
Skip to first unread message

Wesley Moore

unread,
Sep 28, 2008, 2:33:14 AM9/28/08
to cocoah...@googlegroups.com
Hi all,
Working on a Mac app where I want to open a file that doesn't already
exist and write chunks of NSData to it incrementally. NSFileHandle has
a method fileHandleForWritingAtPath: but that requires the file to
already exist. Most of the other file writing routines I found are
designed to write data once and that's it, not keep the handle open to
receive more data.

My solution was along the following lines but it seems mighty ugly.
Anyone know of a better way?

// Open and create the file using POSIX open in <fcntl.h>
int segment_fd = open([segment_file_path UTF8String], O_WRONLY |
O_CREAT | O_APPEND | O_TRUNC, 0666);
NSAssert1(segment_fd >= 0, @"Error opening file descriptor for @%",
segment_file_path);

// Wrap the file descriptor up in an NSFileHandle
segment_file_handle = [[NSFileHandle alloc]
initWithFileDescriptor:segment_fd closeOnDealloc:YES];

// Insert multiple calls to [segment_file_handle writeData:data];

[segment_file_handle closeFile]; // Unnecessary?
[segment_file_handle release]; // Closes fd

Regards,
Wes

Pete Yandell

unread,
Sep 28, 2008, 7:26:37 PM9/28/08
to cocoah...@googlegroups.com

On 28/09/2008, at 4:33 PM, Wesley Moore wrote:

> Working on a Mac app where I want to open a file that doesn't already
> exist and write chunks of NSData to it incrementally. NSFileHandle has
> a method fileHandleForWritingAtPath: but that requires the file to
> already exist. Most of the other file writing routines I found are
> designed to write data once and that's it, not keep the handle open to
> receive more data.
>
> My solution was along the following lines but it seems mighty ugly.
> Anyone know of a better way?

You could use NSFileManager's createFileAtPath:contents:attributes: to
create the file, then open it.

Pete Yandell
http://notahat.com/

Wesley Moore

unread,
Sep 28, 2008, 7:47:19 PM9/28/08
to cocoah...@googlegroups.com
Thanks Pete,
I saw that one mentioned in a post I found online. The suggestion was
to pass it an empty NSData object for contents and then reopen it with
NSFileHandle. That seemed messy as well as it was creating, opening
and closing the file only to reopen it. Although it does remove the
need for all the POSIX flags.

It seems strange I can't find a standard pattern for this. I'd imagine
that most apps that download from a network link would want to write
as they go to a new file. I'll have to do some more researching.

Wes

Wesley Moore

unread,
Sep 28, 2008, 11:42:03 PM9/28/08
to cocoah...@googlegroups.com
I did some further investigation by looking through some open source
Cocoa code I could find. The Adium sources and the Omni Framework
sources.

Adium had a couple of spots where it did what I did and I found one
place in the Omni Frameworks where they did what Pete suggested ie.

[[NSFileManager defaultManager] createFileAtPath:aFilename
contents:[NSData data] attributes:requestedFileAttributes];
newFileHandle = [NSFileHandle fileHandleForWritingAtPath:aFilename];

So it seems either are accepted solutions and there is no "standard" way.

WM

michael lawley

unread,
Sep 30, 2008, 8:38:57 PM9/30/08
to cocoah...@googlegroups.com
Given the lack of any other criteria for choosing, I'd go with the
POSIX API and wrapping the result since it doesn't expose you to a
race condition.

michael

2008/9/29 Wesley Moore <wjm...@gmail.com>:

Wesley Moore

unread,
Sep 30, 2008, 10:29:56 PM9/30/08
to cocoah...@googlegroups.com
Yeah that's same reasoning I came to. I think I'll stick with it for now.
Reply all
Reply to author
Forward
0 new messages