computer organization
c m s c 311  
f a l l   2 0 0 2  

Purpose

The purpose is to load a series of unsigned int (32 bits) from a file. The file will have a 32 bit value (0xdabedabe). As you read it in, it may have been stored in the same endian-ness as your machine or a different endian-ness. (Imagine you have downloaded this file from somewhere on the web, but don't know what endian-ness the machine was).

If you read in an unsigned int equal to 0xdabedabe, then this must mean the file is the same as yours. If it's some other value, then it must be a different endian-ness.

Public Methods

static vector<unsigned int> loadValues( const string & fileName ) ;
If the file exists (in the current directory), read in the first unsigned int, and determine the endian-ness. If this is the same as your machine's endian-ness, read the rest of the values normally. Thus, if there are N * 4 bytes in the file, you will read in (N - 1) unsigned int values (after the initial 4 byte header with 0xdabedabe), and store them in a vector of unsigned ints.

If the endian-ness is not the same as your machine, then you still read in the N - 1 values, but then afterwards, you must convert the values so they are the same endian-ness as your machine. (Thus, for each unsigned int, you must swap bytes 0 and 3 and bytes 1 and 2, assuming byte 0 is the least significant byte, and byte 3 is the most significant byte).

If the file does not exist, then just return an empty vector. You can assume that there is at least 8 bytes in the file if it does exist (i.e., it has the 4 byte header plus at least one 4 byte integer).

static bool writeValues( const string & fileName, vector<unsigned int> values, bool isBigEndian ) ;
In this version, you will write out the values given the endian-ness. Add the header as needed (0xdabedabe). This may involve swapping bytes. If you read in the file, then call this function with the same endian-ness as the file, then print out the file, you should get the equivalent file (you can run "diff" to see if they result in the same binary).

If the file exists, then return false, and don't do anything.

Location of File

Go to ~chf11001/Proj/P2/, and there should be Load.h. Those implementing it in Java should make the appropriate conversions.

Writing Binary Files

In C, to write to a file requires the unistd.h library. You need to open a file to write.
 int fd ; // fd is called a file descriptor
 ssize_t w1, w2 ;
 char header1[ 512 ], header2[ 1024 ] ;

 // Opens a file to be written, but only if file does not already exist.
 if ( ( fd = open( "newfile", O_WRONLY|O_CREAT|O_EXCL, 0644 ) ) == -1 )
   {
      cout << "Error opening file" << endl ;
      return -1 ;
   }

  w1 = write( fd, header1, 512 ) ;
  w2 = write( fd, header1, 1024 ) ;

  // close the file
  close( fd ) ;
The write function takes a file descriptor of an opened file, a pointer to some array (any type) or even just a plain structure or variable, and the number of bytes that will be written. The function returns an int-like value telling you how many bytes were actually written.

To open a file for reading (in C),

 int fd ; // fd is called a file descriptor
 ssize_t n1, n2 ;
 char buf[ 512 ], buf2[ 1024 ] ;

 // Opens a file for read only
 if ( ( fd = open( "oldfile", O_RDONLY ) ) == -1 )
   {
      cout << "Error opening file" << endl ;
      return -1 ;
   }

  n1 = read( fd, buf1, 512 ) ;
  n2 = read( fd, buf2, 1024 ) ;

  // close the file
  close( fd ) ;
Nelson Padua-Perez offers the C++ solution.

Note: you should switch "Person" to unsigned int.

#include <iostream.h>
#include <stdlib.h>
#include <fstream.h>

struct Person
{
   int id;
   float salary;
};

// write takes a char *, and the number of bytes
void create_file(char *filename)
{
   int x;
   Person p;
   
   ofstream out(filename, ios::out);
   if (!out)
   {
      cerr << "File opening failed!" << endl;
      exit(1);
   } 

   for (x = 1; x <= 5; x++)
   {
      p.id = x;
      p.salary = x * 100;
      out.write(reinterpret_cast<const char *>(&p), sizeof(Person));
   }
}

// read takes a char * pointer, and the number of bytes.
// Notice you can store into any object---endian-ness is an
// issue, however.   If the file stores in big-endian, and the machine
// is little-endian, the number will be read in the wrong order.
// There's no information in the file to determine endian-ness.

void read_file(char *filename)
{
   int x;
   Person p;

   ifstream in(filename, ios::in);

   if (!in)
   {
      cerr << "File opening failed!" << endl;
      exit(1);
   }
   
   for (x = 1; x <= 5; x++)
   {
      in.read(reinterpret_cast<char *>(&p), sizeof(Person));
      cout << "ID: " << p.id << " , SALARY " << p.salary << endl;
   }
}

void read_entry(int id, char *filename)
{
   Person p;

   ifstream in(filename, ios::in);
    
   in.seekg((id - 1) * sizeof(Person));
   in.read(reinterpret_cast<char *>(&p), sizeof(Person));
   cout << "SID: " << p.id << " , SSALARY " << p.salary << endl;
}

void write_entry(int id, float salary, char *filename)
{
   Person p;

   ofstream out(filename, ios::out);

   p.id = id;
   p.salary = salary;
   out.seekp((id - 1) * sizeof(Person));
   out.write(reinterpret_cast<const char *>(&p), sizeof(Person));
}

int main()
{
   create_file("data");
   read_file("data"); // sequential reading

   cout << "READING ENTRY" << endl;
   read_entry(2, "data");

   cout << "RANDOM WRITING" << endl;
   write_entry(2, 1345, "data");
   read_entry(2, "data");

   return 0;
}

OUTPUT

% a.out
ID: 1 , SALARY 100
ID: 2 , SALARY 200
ID: 3 , SALARY 300
ID: 4 , SALARY 400
ID: 5 , SALARY 500
READING ENTRY
SID: 2 , SSALARY 200
RANDOM WRITING
SID: 2 , SSALARY 1345
% 

See the class syllabus for policies concerning email
Last Modified: Fri Sep 27 19:41:52 EDT 2002
left up down right home

Web Accessibility