6.11 HOMEWORK


6.11 HOMEWORK

  1. Is this code fragment legal in C++?

          int a[10] = {0};      int i;      int* p;      p = &i;      a = &i; 
  2. Using the vector data structure in C++, write and test the following functions:

    • readAllStrings()

    • readAllInts()

    • readAllDoubles()

    Each function should read all of the data items on a line of the user's terminal and return the items in the form of an array of the appropriate kind. You must also allow the user to put any number of spaces between the entries. Also, there could be an arbitrary number of spaces before the first entry and after the last entry.

  3. Write a Java class TerminallO with the following static methods for terminal IO:

    • readOneString()

    • readOneInt()

    • readOneDouble()

    • readAllStrings()

    • readAllInts()

    • readAllDoubles()

    Each method should read one or all, as the case may be, of the data items on a line of the user's terminal and, for multiple item entry, return the items in the form of an array of the appropriate kind. You must allow the user to enter an arbitrary number of spades between the items, before the first item, and after the last item.

  4. Write a Java class, FileReaderData, with the following static methods and their return types:

    • String[] readAllStrings()

    • int[] readAllInts()

    • double[] readAllDoubles()

  5. As you well know, one cannot always display the content of a file. For example, if a file contains object code, you cannot display it on a screen by reading it as a text file. Yet, it is sometimes useful to peer into such files for diagnostic purposes. This you can do by reading the file one byte at a time and printing out the hex representation of the bytes.

    Write a Java program that creates a hex dump of a file regardless of whether it is an alphanumeric file, a binary file containing object code, or an image or a sound file of some kind. The program should read each byte from the file and print out its two-character hex representation into an output text file. Your program should take command line arguments for the input and the output file names. In other words, after compilation it should be possible to execute your Java program by using an invocation of the following type

          Java class_name in_file_name out_file_name 

    The file out_file_name will be the hex dump of the contents of the file in_file_name. The hex output in the output file should be formatted so as to show the hex characters for 20 bytes at a time. It should look like:

          7f 45 4c 46 1 2 1 0 0 0 0 0 0 0 0 0 0 2 0 2      0 0 0 1 0 1 10 80 0 0 0 34 0 0 34 84 0 0 0 0      0 34 0 20 0 5 0 28 0 19 0 17 0 0 0 6 0 0 0 34           .....              ..... 

    Suggestions:

    1. Since the input can be a binary file, use an input stream of type FileInputStream for reading the file one byte at a time.

    2. The output file will be a regular alphanumeric file (since it will contain the hex characters representing each byte of the input source file). Therefore, you might wish to use a text output stream to feed a binary output stream by invoking

            PrintWriter out =           new PrintWriter( new FileOutputStream( .... ) ); 
    3. Recall that main () is invoked with the parameter args of type String []. What that means is that args [0] will be the input file name and the args [1] the output file name. (Note the difference between the indexing of the command-line arguments in C++ and Java.)

    4. Use the method int read () defined for FileInputStream to read one byte at a time. This method returns-1 for denoting the end of a file.

    5. To create the hex representation of the value returned by read (), use the method Integer.toHexString( int ).

  6. Write a C++ program that creates a hex dump of a file regardless of the nature of the file. Using the no-arg version of the get () function presented in Section 6.8.2,[25] the program should read each byte from the file, as in

          ifstream in( "in_file", ios::binary );      ....      int ch;      while ( ( ch = in.get () ) !=EOF ) {         ....      } 

    and print out its two-character hex representation into an output text file. Your program should take command-line arguments for the input and the output file names. In other words, you should be able to call the program in the following manner:

          a.out in_file out_file 

    The file out_file will be the hex dump of the contents of the otherwise unprintable in_file. The hex output in the output file should be formatted in the same manner as in the previous Java problem, that is it should show the hex characters for 20 bytes at a time.

  7. Rework the previous problem by reading the input file with the read () function described in Section 6.8.3 for reading N bytes at a time, as in

          const int N = 1000;      ....      ifstream in( "in_file", ios::binary );      ....      unsigned char buffer[N];                          //(A)      while ( in.read( buffer, N ) ) {           //output the hex for each byte      } 

    Be sure to use gcount()to get any remaining bytes in the input stream when read()hits the end-of-file condition.

  8. With the help of bit patterns, explain precisely why the following replacement for the declaration in line (A) of the program fragment of the previous problem does not work

          char buffer[N]; 

    With this change, you will see a two-character hex representation for most of the bytes in the input file. But every once in a while it will generate an 8-character hex sequence for a single byte of the input file. This longish looking hex sequence would seem like it was generated by a "negative integer." Why?

  9. A text file with the following integer entries, one per row, is provided to the program shown below. The program tries to read the integers, but instead reads garbage, as shown by the output displayed after the program. Why?

          //file: input.txt      12      12      12      12      12      23 

    The program is

     
    import java.io.*; class Test { public static void main( String[] args ) { try { FileInputStream fin = new FileInputStream("input.txt"); DataInputStream din = new DataInputStream(fin); for (int i = 1; i <= 6; i++) { System.out.println( din.readInt() ); } fin.close(); } catch(IOException e) {System.out.println(e);} } }

    The program produces the following output (the output will vary depending on the underlying architecture of the machine):

          825362993      839528754      170996234      825362994      java.io.EOFException 
  10. As mentioned in Section 6.10, the Java, io package contains stream classes for direct object level I/O. These, as shown in Figure 6.3, are ObjectOutputStream and ObjectInputStream. A Java object can be output directly to an external resource if the class to which the object belongs has implemented the Serializable interface. An object is converted into a stream of bytes so that it can be output via an object stream to, say, a disk file. This process is known as object serialization. The opposite process, namely reading a stream of bytes through an input object stream and converting those those bytes back into an object is known as object serialization. The byte stream produced for an object through serialization includes a 64-bit long serial version UID that is a secure hash of the full class name, its super-interfaces, its members. This unique identifier is used during object input to discover any incompatibilities with the existing classes in the Java Virtual Machine.

    Shown below is a simple class User that is serializable because it implements the Serializable interface. Notice how the object streams are set up in lines (A) and (B) and how the writeObject() method of ObjectOutputStream is invoked to write the objects out to a disk file and how the readObject() method of ObjectInputStream is invoked to read the objects back from the disk file.

     
    //ObjectIO.java import java.io.*; class User implements Serializable { private String name; private int age; public User( String nam, int yy ) { name = nam; age = yy; } public String toString(){return "User: " + name + " " + age;} public static void main( String[] args ) throws Exception { User user1 = new User( "Melinda", 33 ); User user2 = new User( "Belinda", 43 ); User user3 = new User( "Tralinda", 53 ); FileOutputStream os = new FileOutputStream( "object.dat" ); ObjectOutputStream out = new ObjectOutputStream( os ); out.writeObject( user1 ); out.writeObject( user2 ); out.writeObject( user3 ); out.flush(); os.close(); FileInputStream is = new FileInputStream( "object.dat" ); ObjectInputStream in = new ObjectInputStream( is ); User user4 = (User) in.readObject(); User user5 = (User) in.readObject(); User user6 = (User) in.readObject(); is.close(); System.out.println( user4 ); System.out.println( user5 ); System.out.println( user6 ); } }

    The straightforward approach shown above works only for simple classes. For a more complex class, such as when the class User is provided with an array data member, this approach would not work. Now you would need to provide the class with two methods of the following exact signatures:

          private void writeObject( ObjectOutputStream out )                throws IOException      private void readObject( ObjectInputStream in )                throws IOException, ClassNotFoundException 

    When a class is endowed with these functions, the ObjectOutputStream's writeObject will call the writeObject method defined as above for the serialization process. The same goes for the ObjectInputStream's readObject method vis-à-vis the readObject defined as above for the class in question.

    The goal of this homework is to create a serializable version of the following class by providing implementation code for the methods writeObject and readObject in accordance with the signatures shown above. Your implementation of these methods would need to write out each data member of the class and each element of the array separately by using the writeInt and writeString (or writeUTF) methods of the ObjectOutputStream class. To deserialize the byte streams, you'd need to use the readInt and readString (or readUTF) of the ObjectInputStream class for each data member of the class and also for each element of the array.[26]

          class User implements Serializable {           private String name;           private int age;           transient private String[] children;           private int numChildren;           // constructor(s)           // implementation code for writeObject()           // implementation code for readObject()      } 

[25]While it is true that Section 6.8.2 deals with text file I/O, but, as was mentioned in Section 6.8.3, the get () functions of Section 6.8.2 can also be used to read the bytes in a binary file provided the file is opened in the binary mode.

[26]Note that we have marked the array data member children as transient. You declare a class data member transient if you do not want it to be serialized. So for the class shown we do not want the array reference to be serialized; however, you'd still want to serialize each element of the array. Your implementation code for the readObject method should then create a fresh array reference for children and then read off each element of the array from the byte stream into the array.




Programming With Objects[c] A Comparative Presentation of Object-Oriented Programming With C++ and Java
Programming with Objects: A Comparative Presentation of Object Oriented Programming with C++ and Java
ISBN: 0471268526
EAN: 2147483647
Year: 2005
Pages: 273
Authors: Avinash Kak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net