Beginning Java for Xojo Programmers IX

This time around we’ll look at files
But I also intend to make more use of VS Code

Make a new directory for the code for this session. I called min e_IX - Files_ and, in VS Code opened that directory

Create a new file

And set its LANGUAGE to Java by clicking on the blue hyperlinked Select a Language text

and select Java from the list

Save this as Files.java

and now the “project” should appear with that item in the list
Screen Shot 6

Now we can start writing out code
Let suppose we want a simple app that can read a file, and echo its contents to a terminal window.

The first thing we will do is write out “application class”
Since the NAME of a file in Java also has to match the name of the principal class IN that file our Application class name is “Files”

So our declaration for this file should look like

   class Files {

  }

This class declaration is perfectly fine.
IF you try to RUN this java file by right clicking the file in the project browser and selecting Run Java or Debug Java from the contextual menu you will get an error.
Screen Shot 7

By default a java class, when you try to RUN it, needs to have a main function. Xojo does as well just the IDE hides this from you so you dont have to think about it.

You then need a main method for the Java runtime to start the app.
If you create it as

 public void main(String[] args ) {

 }

it is SYNTACTICALLY valid - but again you will get an error. The reason is that this main method SHOULD ALWAYS be defined as “public static void” so the runtime can call it without having to create an instance of our principal class. In fact in Java the MAIN method should always be public, static, void because :

  • In any Java program, the main() method is where the runtime starts execution.
  • If the main() is allowed to be non-static, then to call the main() method the runtime has to create an instance of the class
  • To create an instance the constructor has to be called. It will be ambiguous if the constructor of that class takes an argument.
  • A static method of a class can be called by using the class name only without creating an instance. ( Note this is like Xojo’s SHARED methods in a class )
  • The main() method in Java must be declared public, static and void. If any of these are missing, the Java program will compile but a runtime error will be thrown when you try to RUN that class as the main entry point

Alter the declaration for MAIN to :

 public static void main(String[] args ) {

 }
  • public means the method is usable by any code OUTSIDE this class
  • static means this method can be called without needing an instance
  • void means there is NO return value from a call to this method

So far our code doesnt do much except execute. And do nothing.
Lets make it so this little app takes one, or more, file names as arguments and echos each file in turn to the terminal window its run in.
Our initial declaration already has the “arguments” parameter that is passed to the main method - thats String[] args which says that there is a String array passed to the main method that can be referred to using the local variable name args

So we can check that there are 1 or more arguments passed.

   if (args.

aside IF VS code is NOT autocompleting for you open Preferences > Text Editor > Suggestions and click on the “edit in settings.json” under Quick Suggestions (personally I find this horrid UI but …)

In my case this json looks like

{
    "editor.suggestSelection": "first",
    "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
    "files.exclude": {
        "**/.classpath": true,
        "**/.project": true,
        "**/.settings": true,
        "**/.factorypath": true
    },
    "editor.quickSuggestions": true
}

Make sure editor.quickSuggestions has a true value. Save your work and the changes to the settings.json and restart VS Code an d you should now have autocompletion

back
So we can check that there are 1 or more arguments passed. If none are passed then we just print a suitable message and exit

  if ( args.length < 1 ) {
      System.out.println("nothing to do") ;
   }

If there ARE arguments then we’ll open each file, and print the contents. The easiest way to iterate every string in args is with a Java foreach

   if ( args.length < 1 ) {
      System.out.println("nothing to do") ;
   }

   for (String filepath : args) { // in xojo this would be for each filepath as string in args

      System.out.println("filepath = [" + filepath + "]") ;

   }

Now if you run you will still see that the app, so far, still has no arguments passed to it.
In VS code there are a couple ways to configure your app for debugging.
For THIS testing I find the easiest is to use a Terminal window or to switch the lower panel in VS code to use a terminal. Click on the java process console and switch to zsh and we’ll run from the command line

In my case switching to the command line means I need to compile the code

javac Files.java

Then run it

java Files

and now to add arguments I can just drag files into this terminal window and I get properly quoted arguments

and when do run we see

npalardy@server IX- FIles % java Files '/Users/npalardy/Desktop/INN Beginning Java/IX- FIles/Files.java'
filepath = [/Users/npalardy/Desktop/INN Beginning Java/IX- FIles/Files.java]
npalardy@server IX- FIles % 

1 argument and one output

If we run with multiple arguments we see one per argument

npalardy@server IX- FIles % java Files '/Users/npalardy/Desktop/INN Beginning Java/IX- FIles/Files.java' '/Users/npalardy/Desktop/INN Beginning Java/IX- FIles/Files.class'
filepath = [/Users/npalardy/Desktop/INN Beginning Java/IX- FIles/Files.java]
filepath = [/Users/npalardy/Desktop/INN Beginning Java/IX- FIles/Files.class]
npalardy@server IX- FIles % 

So far so good. Now to take that file oath and open the file & print the contents out !
In Xojo taking that argument and turning it into a file we can list the contents of means you need to

  1. take the file path and get a folderitem for it
  2. open either a text input stream or binary stream so you can read the file
    The process is the same in Java
    However, in java you MUST tell the compiler which classes each file is going to use. It does not include much by default as the possible number of java libraries that you might need is huge and including all of them could make your Java application VERY bloated. Xojo by default includes the entire framework and then may strip out portions you have not used.

In order to use many filesystem related API’s we need to IMPORT java.io
Javas import system is very flexible and you can import one single class, a whole hierarchy or anything in between
Make the first line in our app

  import java.io.* ;

and this will make the file system related input output mechanisms we’ll need be included so we can just use them.
In java the File object is more or less the equivalent of the Xojo Folderitem

To get a reference to a File we need to create one using the path to a file
That would be something like

 File file = new File(filepath); 

In Java just like in Xojo a fpath may refer to a file that does not exist
So we need to handle that

      if (file.exists() == false) {
         System.out.println("filepath = [" + filepath + "] does not exist") ;
         continue ;
      }

Now that we have a valid reference to a file that exists we can proceed to actually open the file & print its contents

 FileInputStream fis = new FileInputStream(file);     

 int r=0;  
 while((r=fis.read())!=-1)  
 {  
     System.out.print((char)r);      //prints the content of the file  
 }

FileInputStream is MOST analogous to Xojo’s BinaryStream (although it is READ ONLY by default)

So this code opens the stream and then reads byte by byte until it gets to the end of the file and prints a character for every byte as it goes

However, the while loop demonstrates something that is simple to do in Java that is also quite odd to read

The inner most statement

 (r=fis.read())

reads 1 byte and assigns it to r

 ((r=fis.read())!=-1)  

In java an assignment, like (r=fis.read()), has a value so it can be compared to other values
And thats what happens
File InputStreams return -1 when there is no more data
(FileInputStream (Java Platform SE 7 ))

System.out.print(char(r)) prints the character value to the standard output stream

AT this point the code looks like

import java.io.* ;  

class Files {

 public static void main(String[] args ) {

   if ( args.length < 1 ) {
      System.out.println("nothing to do") ;
   }

   for (String filepath : args) {

      System.out.println("filepath = [" + filepath + "]") ;

      File file = new File(filepath); 

      if (file.exists() == false) {
         System.out.println("filepath = [" + filepath + "] does not exist") ;
         continue ;
      }

      FileInputStream fis = new FileInputStream(file);     
      
      int r=0;  
      while( (r=fis.read())!=-1)  
      {  
         System.out.print((char)r);      //prints the content of the file  
      }  

   }
 }
}

there is however one issue
If you compile this code you get an error

npalardy@server IX- FIles % javac Files.java    
Files.java:22: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileInputStream fis = new FileInputStream(file);     
                            ^
Files.java:25: error: unreported exception IOException; must be caught or declared to be thrown
      while( (r=fis.read())!=-1)  
                        ^
2 errors

Remember that Java, unlike Xojo, REQUIRES you to either explicitly handle possible exceptions OR declare that your method is going to throw them.
And Java also documents ALL possible exceptions that a method might throw so its easy to know what you might have to handle.

So we’ll adjust the code to explicitly catch that possible exception

import java.io.* ;  

class Files {

   public static void main(String[] args ) {

      if ( args.length < 1 ) {
         System.out.println("nothing to do") ;
      }

      for (String filepath : args) {

         System.out.println("filepath = [" + filepath + "]") ;

         File file = new File(filepath); 

         if (file.exists() == false) {
            System.out.println("filepath = [" + filepath + "] does not exist") ;
            continue ;
         }

         try {
            FileInputStream fis = new FileInputStream(file);     

            int r=0;  
            while( (r=fis.read())!=-1)  
            {  
               System.out.print((char)r);      //prints the content of the file  
            }  
         }
         catch (FileNotFoundException; fnf) {
         // we're not going to do anything
         }
      }
   }
}

If you try to compile now there STILL is one exception to catch

npalardy@server IX- FIles % javac Files.java
Files.java:26: error: unreported exception IOException; must be caught or declared to be thrown
            while( (r=fis.read())!=-1)  
                              ^
1 error
npalardy@server IX- FIles % 

When you read from the file something could go wrong
It could have gone missing between opening and trying to read the first time.
So if we catch the exception outside the while lop we’ll quit the while loop and just move on to the next file

The final code looks like

import java.io.* ;  

class Files {

   public static void main(String[] args ) {

      if ( args.length < 1 ) {
         System.out.println("nothing to do") ;
      }

      for (String filepath : args) {

         System.out.println("filepath = [" + filepath + "]") ;

         File file = new File(filepath); 

         if (file.exists() == false) {
            System.out.println("filepath = [" + filepath + "] does not exist") ;
            continue ;
         }

         try {
            FileInputStream fis = new FileInputStream(file);     

            int r=0;  
            while( (r=fis.read())!=-1)  
            {  
               System.out.print((char)r);      //prints the content of the file  
            }  
         }
         catch (FileNotFoundException fnf) {
            // we're not going to do anything
         }
         catch ( IOException iox ) {
            // we're not going to do anything
         }

      }
   }
}

Run it and play around with it and get a good feel for the things we’ve done

References
File - File (Java Platform SE 8 )
FileInputStream - FileInputStream (Java Platform SE 7 )
Oracle Getting Started - Lesson: A Closer Look at the "Hello World!" Application (The Java™ Tutorials > Getting Started)

4 Likes