Best way to do simple binary file I/O?

  • In C, I would just define a struct

    typedef struct _mytype {
      /* field definitions */
      } MyType, *MyTypePtr;

    then, in code somewhere...

    ...
    FILE *fp;
    int i;

    ...
    fp = fopen(<filename>, "rb");
    i = fread(fp, sizeof(MyType), 1);
    while (<some condition based on what was read in>)
      {
      /* Process one record... */
      ...

      /* Read another */
      i = fread(fp, sizeof(MyType), 1);
      }
    fclose(fp);
    ...

    What's the ObjC (OO) recommended methodology for this now? (for just
    a Core Foundation tool)
  • On Dec 28, 2007, at 9:23 PM, William Squires wrote:

    > In C, I would just define a struct
    >
    > typedef struct _mytype {
    > /* field definitions */
    > } MyType, *MyTypePtr;
    >
    > then, in code somewhere...
    >
    > ...
    > FILE *fp;
    > int i;
    >
    > ...
    > fp = fopen(<filename>, "rb");
    > i = fread(fp, sizeof(MyType), 1);
    > while (<some condition based on what was read in>)
    > {
    > /* Process one record... */
    > ...
    >
    > /* Read another */
    > i = fread(fp, sizeof(MyType), 1);
    > }
    > fclose(fp);
    > ...
    >
    > What's the ObjC (OO) recommended methodology for this now? (for just
    > a Core Foundation tool)

    NSFileHandle

    ___________________________________________________________
    Ricky A. Sharp        mailto:<rsharp...>
    Instant Interactive(tm)  http://www.instantinteractive.com
  • Just as a reminder: Raw binary I/O like this is likely
    to break across architectures. It also doesn't mesh
    very well with Cocoa objects, whose internal structure
    is generally private. The safer and more standard
    Cocoa way of doing it would be either to write an
    XML/plist document or to archive objects with
    NSKeyedArchiver.

    Cheers,
    Chuck

    --- William Squires <wsquires...> wrote:

    > In C, I would just define a struct
    >
    > typedef struct _mytype {
    > /* field definitions */
    > } MyType, *MyTypePtr;
    >
    > then, in code somewhere...
    >
    > ...
    > FILE *fp;
    > int i;
    >
    > ...
    > fp = fopen(<filename>, "rb");
    > i = fread(fp, sizeof(MyType), 1);
    > while (<some condition based on what was read in>)
    > {
    > /* Process one record... */
    > ...
    >
    > /* Read another */
    > i = fread(fp, sizeof(MyType), 1);
    > }
    > fclose(fp);
    > ...
    >
    > What's the ObjC (OO) recommended methodology for
    > this now? (for just
    > a Core Foundation tool)
    >

          ____________________________________________________________________________________
    Be a better friend, newshound, and
    know-it-all with Yahoo! Mobile.  Try it now.  http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
  • > i = fread(fp, sizeof(MyType), 1);

    This is not portable across CPU architectures. You have to take care of
    byte-swapping between PPC & Intel. There may also be issues with padding.

    Other than that, I'd say do the same thing in Objective-C.

    --
    Scott Ribe
    <scott_ribe...>
    http://www.killerbytes.com/
    (303) 722-0567 voice
  • I don't see why that code wouldn't work, as objective-c is a variation
    of the c language and can use of all of it's standard libraries.

    That said its not a very good idea, because storing the raw
    representation from memory will cause incompatibilty across
    architechtures, as well as with cocoa data types.

    Omar Qazi
    Synergick Software
    1.310.294.1593

    On Dec 28, 2007, at 7:23 PM, William Squires <wsquires...>
    wrote:

    > In C, I would just define a struct
    >
    > typedef struct _mytype {
    > /* field definitions */
    > } MyType, *MyTypePtr;
    >
    > then, in code somewhere...
    >
    > ...
    > FILE *fp;
    > int i;
    >
    > ...
    > fp = fopen(<filename>, "rb");
    > i = fread(fp, sizeof(MyType), 1);
    > while (<some condition based on what was read in>)
    > {
    > /* Process one record... */
    > ...
    >
    > /* Read another */
    > i = fread(fp, sizeof(MyType), 1);
    > }
    > fclose(fp);
    > ...
    >
    > What's the ObjC (OO) recommended methodology for this now? (for just
    > a Core Foundation tool)
  • I don't see why you can't use the standard C file I/O functions
    (fopen, fread etc) in Objective C. I have been doing this for a long
    time on both Intel and PPC machines and have had no problems. By the
    way doesn't fread have four parameters ?

    Jim Merkel

    Charles Steinman wrote:
    > Just as a reminder: Raw binary I/O like this is likely
    > to break across architectures. It also doesn't mesh
    > very well with Cocoa objects, whose internal structure
    > is generally private. The safer and more standard
    > Cocoa way of doing it would be either to write an
    > XML/plist document or to archive objects with
    > NSKeyedArchiver.
    >
    > Cheers,
    > Chuck
    >
    > --- William Squires <wsquires...> wrote:
    >
    >> In C, I would just define a struct
    >>
    >> typedef struct _mytype {
    >> /* field definitions */
    >> } MyType, *MyTypePtr;
    >>
    >> then, in code somewhere...
    >>
    >> ...
    >> FILE *fp;
    >> int i;
    >>
    >> ...
    >> fp = fopen(<filename>, "rb");
    >> i = fread(fp, sizeof(MyType), 1);
    >> while (<some condition based on what was read in>)
    >> {
    >> /* Process one record... */
    >> ...
    >>
    >> /* Read another */
    >> i = fread(fp, sizeof(MyType), 1);
    >> }
    >> fclose(fp);
    >> ...
    >>
    >> What's the ObjC (OO) recommended methodology for
    >> this now? (for just
    >> a Core Foundation tool)
    >
  • On Dec 28, 2007, at 10:23 PM, William Squires wrote:

    > the ObjC (OO) recommended methodology for this now? (for just a Core
    > Foundation tool)

    Hello,

    I just finished writing a framework that utilizes NSFileHandle and
    NSData to do exactly this. NSFileHandle has a very simple API. Getting
    the data as NSData is useful if you'll be operating on it with other
    Cocoa API. Saves some steps. NSFileHandle also has callbacks for
    flushing the data to disk. So you can add useful hooks in your code.

    hope that helps,

    Jaime
  • On 29.12.2007, at 8:31 , James Merkel wrote:
    > Charles Steinman wrote:
    >> Just as a reminder: Raw binary I/O like this is likely
    >> to break across architectures. It also doesn't mesh
    >> very well with Cocoa objects, whose internal structure
    >> is generally private. The safer and more standard
    >> Cocoa way of doing it would be either to write an
    >> XML/plist document or to archive objects with
    >> NSKeyedArchiver.
    >
    > I don't see why you can't use the standard C file I/O functions
    > (fopen, fread etc) in Objective C. I have been doing this for a long
    > time on both Intel and PPC machines and have had no problems. By the
    > way doesn't fread have four parameters ?

      If you take account of some differences, fread() or any other raw
    read/write method is OK. If you're saving objects, they are
    effectively structs for this discussion. Also, NSObject's ivars are
    private, so you can't save those, and need to re-create the right
    subclass after loading an object, too. NS(Keyed)Archiver and Co. take
    care of that for you. So, if you're not doing something that needs to
    be loaded partially and needs to be random access, an archiver is
    usually less hassle.

      If you're using fread() the way the OP mentioned, then either you're
    saving only one-byte quantities (like ASCII or UTF8 text, or uint8_t
    and char types) or you never tried to take one of your files from an
    Intel Mac to a PPC Mac or the other way round:

      The endian-ness (order in which the individual bytes of a multi-byte
    type like an int are stored (sizeof(int)==4 on 32-bit MacOS X builds))
    differs between those platforms, and if you save on one platform and
    read on the other, your numbers get 'reversed' and you get nonsense
    numbers.

      The usual solution is to either save everything in one computer's
    endian-ness and have all others convert, or to store a byte-order
    marker at the start of the file (e.g. the number 1 as a short, which
    is 0x0100 on Intel, and 0x0001 on PPC), and then to convert if the
    number is not 1.

      Of course, if you save a whole struct, padding bytes that get
    inserted into structs to force better performance by aligning fields
    on their native boundaries can screw you over, because those can
    differ depending on CPU. I think on OS X most of the types are the
    same, but IIRC there were a few that didn't (floats? I'd have to check
    my file access library). I generally don't save whole structs, and
    rather each field separately, as you'd do with NSArchiver.

    Cheers,
    -- M. Uli Kusterer
    "The Witnesses of TeachText are everywhere..."
    http://www.zathras.de
previous month december 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today