Question

I ran into an issue trying to read from a DataOutputStream with a Scanner. The following code fails with an input mismatch exception.

    DataOutputStream o = new DataOutputStream(new FileOutputStream("temp"));
    o.writeByte(1);
    o.flush(); o.close();

    Scanner i = new Scanner(new FileInputStream("temp"));
    System.out.println(i.nextByte());
    i.close();

So what output streams ARE compatible with Scanner? And is there an Output/Input stream pair that are built for reading and writing all the primitive types and string lines? I really wanted a non-deprecated readLine() method, and all the input streams I've seen that have that method are deprecated.

EDIT: The input and output streams will be across sockets for a Client/Server application. Here is the entire relevant code for each side:

SERVER

package server;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Scanner;

/**
 * Server class handles all clients that wish to read a file stored on this
 * server's
 * database. Also connects to other servers to share some information.
 *
 * @author Josh Wilkins
 */
public class Server{

//Server message type constants
private static final byte REPLY = 0;
private static final byte YES = 1;
private static final byte NO = 2;
private static final byte UPDATE = 3;

private final int id;
private final ServerSocket fileServer;      //connection point for clients
private HashMap<String, FileObject> files;  //list of files in database, hashed by file name

/**
 * Creates a new file server with given id on the specified port.
 * <p>
 * @param id
 * @param port
 * <p>
 * @throws IOException
 */
public Server(int id, int port) throws IOException{
    this.id = id;
    fileServer = new ServerSocket(port);
    files = new HashMap<>();
}

/**
 * Loops forever, accepting new clients and creating threads to handle
 * them.
 * <p>
 * @throws IOException
 */
public void acceptClients() throws IOException{
    while( true ){
        Socket client = fileServer.accept();
        (new ClientHandler(client)).run();
    }
}

/**
 * Sends most updated version of specified file to specified server. Will
 * only send update if the server should host the file. UNIMPLEMENTED.
 * <p>
 * @throws UnsupportedOperationException
 */
private void sendUpdate(int server, FileObject file){
    //TODO
    throw new UnsupportedOperationException("Not supported yet.");
}

/**
 * Creates a new file in the database with the file name contained in the
 * string file.
 * <p>
 * @param file the file name of the new file object
 */
private synchronized void createFileObject(String file){
    //TODO: Reject files not hashed to this server
    try{
        files.put(file, new FileObject(file));
    } catch(IOException ex){
        System.err.println("Failed to create file: " + file);
        ex.printStackTrace(System.err);
    }
}

/**
 * Determines if this server is allowed to initiate a write request for a
 * file by giving the client the most current version number.
 * <p>
 * @param file the file name of the file in question
 * <p>
 * @return true if allowed to initiate, false otherwise
 */
private boolean canInitiate(String file){
    int hash0 = file.hashCode() % 7;
    int hash1 = (file.hashCode() + 1) % 7;
    return id == hash0 || id == hash1;
}

/**
 * Threaded class to handle all requests from a single client connection.
 */
class ClientHandler extends Thread{
    //Client message type constants
    private static final byte READ = 0;
    private static final byte WRITE = 1;
    private static final byte COMMIT = 2;
    private static final byte ABORT = 3;

    private Socket client;
    private DataOutputStream out;
    private Scanner in;
    private HashMap<String, Integer> pendingUpdates;

    /**
     * Sets up data input and output streams from given client socket.
     * <p>
     * @param client the socket that this client is connected to
     */
    public ClientHandler(Socket client) throws IOException{
        this.client = client;
        out = new DataOutputStream(client.getOutputStream());
        in = new Scanner(client.getInputStream());
        pendingUpdates = new HashMap<>();
    }

    /**
     * Listens for messages coming from client until the connection is
     * closed on the client side.
     */
    @Override
    public void run(){
        //Loops until the client closes the connection, then hasNext returns false
        while( in.hasNext() ){
            //wait for the next message type to be written to the stream
            byte msgType = in.nextByte();
            switch( msgType ){
                case READ:
                    parseRead();
                    break;
                case WRITE:
                    parseWrite();
                    break;
                case COMMIT:
                    parseCommit();
                    break;
                case ABORT:
                    parseAbort();
                    break;
                default:
            }
        }

        //connection is no longer needed, try to clean everything up
        try{
            in.close();
            out.close();
            client.close();
        } catch(IOException ex){
            System.err.println("Failed to close client at " + client.getInetAddress());
            ex.printStackTrace(System.err);
        }
    }

    /**
     * Parses read message from client by collecting data from the input
     * stream and processing it. Assumes the message type byte has already
     * been read. If the file exists in the database, its contents are
     * written to the client, otherwise a null string is written.
     */
    private void parseRead(){
        //TODO: Reject files not hashed to this server
        String file = in.nextLine().trim();    //get requested file name (should end with \n)
        String contents = "";
        if( files.containsKey(file) ){
            try{
                contents = files.get(file).getContents();
            } catch(IOException ex){
                System.err.println("Error reading from file: " + file);
                ex.printStackTrace(System.err);
            }
        } else {
            //TODO:  Need to decide how to handle no such file
            //          - create file and return empty
            //          - just return empty, but don't create
            //          - return some error indicator (change file to "-1" or "File Not Found")
            contents = "";
        }
        //send REPLY message to client
        sendReply(file, contents);
    }

    /**
     * Parses write message from client by collecting data form the input
     * stream and processing it. Assumes the message type byte has already
     * been read. If the file does not exist, one is created immediately
     * regardless of further success. If the version number is viable, or
     * if this server can initiate a write for the given file, the update is
     * queued with the respective FileObject. The client is sent a YES or
     * NO answer depending on success of queueing the update.
     */
    private void parseWrite(){
        //TODO: Reject files not hashed to this server
        int version = in.nextInt();                         //get version first
        String file = in.nextLine().trim();                 //get file name
        String contents = in.useDelimiter("\\Z").next();    //read entire remaining stream for contents
        boolean queued = false;

        //Create file if it does not exist yet.
        if( !files.containsKey(file) ){
            createFileObject(file);
        }

        //queue update to file object
        try{
            //only queue if version is given or if this server can initiate
            if( version > 0 ){
                queued = files.get(file).queueUpdate(contents, version);
            } else if( version < 0 && canInitiate(file) ){
                queued = files.get(file).queueUpdate(contents);
                version = files.get(file).getVersion() + 1;
            }
        } catch(IOException ex){
            System.err.println("Failed to queue update to: " + file);
            ex.printStackTrace(System.err);
        }

        //send response to client (positive if queued, negative if not)
        if( queued ){
            //TODO: What happens if an update is already queued?
            pendingUpdates.put(file, version);
            sendYes(version, file);
        } else {
            sendNo(file);
        }
    }

    /**
     * Parses commit message from client by collecting data form the input
     * stream and processing it. Assumes the message type byte has already
     * been read. If valid server id is read from the stream, an update
     * message is sent to that server for the file. No response is sent to
     * client.
     */
    private void parseCommit(){
        //TODO: Reject files not hashed to this server
        int failed = in.nextInt();
        String file = in.nextLine().trim();
        //TODO: Handle improper commit (no pending update)
        int version = pendingUpdates.remove(file);
        try{
            files.get(file).commitUpdate(version);
        } catch(IOException ex){
            System.err.println("Failed to commit: " + file + " v. " + version);
            ex.printStackTrace(System.err);
        }
        if( failed >= 0 ){
            sendUpdate(failed, files.get(file));
        }
    }

    /**
     * Parses abort message from client by collecting data form the input
     * stream and processing it. Assumes the message type byte has already
     * been read. Simply removes the pending update from the queues. No
     * response is sent to the client.
     */
    private void parseAbort(){
        //TODO: Reject files not hashed to this server
        String file = in.nextLine().trim();
        int version = pendingUpdates.remove(file);  //if no update is queued this simply returns null
        //what happens if:
        // Integer xObj = null;
        // int x = xObj;
        // print(x);
        try{
            files.get(file).abortUpdate(version);
        } catch(IOException ex){
            System.err.println("Failed to abort: " + file + " v. " + version);
            ex.printStackTrace(System.err);
        }
    }

    /**
     * Sends reply message to client. Assumes partial failure is impossible.
     * <p>
     * @param file     name of file
     * @param contents data contained in file
     */
    public void sendReply(String file, String contents){
        try{
            out.writeByte(REPLY);
            out.writeChars(file + "\n");  //end file name with CR for easy reading
            out.writeChars(contents);
        } catch(IOException ex){
            System.err.println("Error sending REPLY(" + file + ", <" + contents.length() + ">)");
            ex.printStackTrace(System.err);
        }
    }

    /**
     * Sends yes message to client. Assumes partial failure is impossible.
     * <p>
     * @param version this updates version number
     * @param file    name of file
     */
    public void sendYes(int version, String file){
        try{
            out.writeByte(YES);
            out.writeInt(version);
            out.writeChars(file + "\n");
        } catch(IOException ex){
            System.err.println("Error sending YES(" + version + ", " + file + ")");
            ex.printStackTrace(System.err);
        }
    }

    /**
     * Sends reply message to client. Assumes partial failure is impossible.
     * <p>
     * @param file name of file
     */
    public void sendNo(String file){
        try{
            out.writeByte(NO);
            out.writeChars(file + "\n");
        } catch(IOException ex){
            System.err.println("Error sending NO(" + file + ")");
            ex.printStackTrace(System.err);
        }
    }
}
}

CLIENT

import java.io.*;
import java.net.Socket;
import java.util.Random;
import java.util.Scanner;
/**
 * Client will take as input the operations (WRITE or READ), the file it wishes to use,
 * and the servers in the network. The client will attempted to connect to three servers 
 * when a WRITE is chosen and a random server for READ.  The servers ranges for READ and WRITE
 * are based on a hashed value of the file name + the next in the line.  
 * example: Sever 1 , Server 2 and Server 3;
 * 
 * @author kattex
 */
public class Client {
private Socket socket = null;
private Scanner inputStream = null;
private DataOutputStream outputStream = null;
private boolean isConnected = false;
private int sequenceNumber = -1;
private int response = 0;
private byte READ = 0;
private byte WRITE = 1;
private byte COMMIT = 2;
private byte ABORT = 3;
private byte YES = 1;
private byte NO = 2;
private byte REPLY = 0;

 /**
 * Connect with server code running in local host or in any other host
 */
private void connect(String address, int port) {
        try {
           // socket = new Socket("localHost", 4445);
            System.out.println(address + "     "  + port);
            socket = new Socket(address, port);
            //outputStream = new ObjectOutputStream(socket.getOutputStream());
            outputStream = new DataOutputStream(socket.getOutputStream());
            inputStream = new Scanner(socket.getInputStream());
            isConnected = true;
        } catch (IOException e) {
            System.out.println("Unable to connect to server " + address);
        }
}

/*
 * Create a random integer within a min and max range
 */
public static int randInt(int min, int max, int count) {
    Random rand = new Random();
    System.out.println("randInt: " + min +  "," + max + "," + count);
    int randomNum = rand.nextInt((max - min) + 1) + min;
    if (randomNum > count){
         randomNum = randomNum % count;
        if (randomNum < 0){
            randomNum += count;
        }
    }
    System.out.println("Random value: " + randomNum);   
    return randomNum;
}
/*
 * Generate hash value for server numbers
 */
public static int hashFileName(String fileName, int serverCount){
    int number = fileName.hashCode() % serverCount;
    if (number < 0){
        number += serverCount;
    }
    System.out.println("Hash Number: " + number);
    return number;
}
/*
 * Write out the contents to a file, if the file does not exist create it
 */
public static void CreateFile(String filename, String content){
    try {
    File file = new File(filename);
    // if file doesnt exists, then create it
    if (!file.exists()) {
        file.createNewFile();
    }
    FileWriter fw = new FileWriter(file.getAbsoluteFile());
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(content);
    bw.close();
    System.out.println("Done");
} catch (IOException e) {
            System.out.println("Erro creating file");
    e.printStackTrace();
}
}
/*
 * Find the next server in the list
 */
public static int nextServer(int number, int count){
    int nextInt;
    number++;
    nextInt = number % count;
    if (number < 0){
        number += count;
    }
    return nextInt;
}
/*
 * Send the WRITE messaget to server
 */
 private void sendWrite(String obj){
    try {
        System.out.print("Pause...");
        (new Scanner(System.in)).nextLine();
        outputStream.writeByte(WRITE);
        System.out.print("Pause...");
        (new Scanner(System.in)).nextLine();
        outputStream.writeInt(sequenceNumber);
        System.out.print("Pause...");
        (new Scanner(System.in)).nextLine();
        outputStream.writeChars(obj);
        outputStream.writeChar('\n');
        System.out.print("Pause...");
        (new Scanner(System.in)).nextLine();
        String contents = readFile(obj);
        System.out.println("Contents of file " + obj);

        outputStream.writeChars(contents);
        System.out.print("Pause...");
        (new Scanner(System.in)).nextLine();

        System.out.println("sending message to server");
        int msgType = inputStream.nextByte();
        if (msgType == YES){            
            sequenceNumber = inputStream.nextInt();
            String tempFileName = inputStream.nextLine().trim();   
            response = 1;
            System.out.println("Receved YES for file " + tempFileName);
        }
        if (msgType == NO){
            String tempFileName = inputStream.nextLine();
            System.out.println("Receved NO for file " + tempFileName);
        }
    } catch (IOException e) {
       System.out.println("Error writing WRITE message to server");
       e.printStackTrace(System.err);
    } 
}  
 /*
  * Read the file into a string that can be sent throught a TCP socket
  */
public String readFile(String fileName) throws FileNotFoundException{
    String output = new Scanner(new File(fileName)).useDelimiter("\\Z").next();
    System.out.println("File output in READFile" + output);
    return output;
}
/*
 * Send Abort message to the server
 */
public void sendAbort(String obj){
    try {
        outputStream.writeByte(ABORT);
        outputStream.writeChars(obj);
        outputStream.writeChar('\n');        

        System.out.println("sending abort message to server");
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("Error sending ABORT message to server");
    }    
}
/*
 * Send commit to Server
 */
public void sendCommit(int Fsvr, String obj){
    try {
        outputStream.writeByte(COMMIT);
        outputStream.writeInt(Fsvr);
        outputStream.writeBytes(obj);
        System.out.println("sending Commit message to server");
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("Error sending COMMIT message to server");
    }    
} 
/*
 * Send READ request
 */
public void sendREAD(String obj){

    String u;
    try {
        outputStream.writeByte(READ);
        outputStream.writeChars(obj); 
        outputStream.writeChar('n');
        System.out.println("sending READ Request message to server");   
        byte type = inputStream.nextByte();
        //File fl = new File(obj);
        if (type == REPLY){
            String file = inputStream.nextLine().trim();
            String contents = inputStream.useDelimiter("\\z").next(); 
            CreateFile(file, contents);
        }        
    } catch (IOException e) {
        e.printStackTrace();
        System.out.println("Erorro sedning READ Request message to server");
    }    
}
/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    Client client = new Client();

    int serverCount = 0;
    int FSvr = -1;

    int length = args.length;
    String Object = "j.txt";
    String type = "write";

    int hashValue = hashFileName(Object, 7);     
    if (type.equals("write") ){

        Client client2 = new Client();
        Client client3 = new Client();
        client.connect("localhost", 4445);

        if (client.isConnected){
            client.sendWrite(Object);
            if (client.response == 1){
                client2.sequenceNumber = client.sequenceNumber;
            }
        }

        int nextValue = nextServer(hashValue,7); 

        //need to add commit message
        int thirdValue = 3;
        System.out.println("Server Numbers " + hashValue + " " + nextValue + " " + thirdValue);
        serverCount = client.response + client2.response + client3.response;
        System.out.println("Servercount " + serverCount);

        if (serverCount >= 2){
            if(client.response != 1 ){FSvr = hashValue; }
            if(client2.response != 1){FSvr = nextValue; }
            if(client3.response != 1){FSvr = thridValue;}

            if(client.response ==  1){client.sendCommit( FSvr,Object);}
            if(client2.response == 1){client2.sendCommit(FSvr,Object);}
            if(client3.response == 1){client3.sendCommit(FSvr,Object);}               

        }else{
            if(client.response == 1 ){client.sendAbort(Object); }
            if(client2.response == 1){client2.sendAbort(Object);}
            if(client3.response == 1){client3.sendAbort(Object);}
        }      
    } else {
        if (type.equals("read")){
            int RValue = randInt(hashValue, hashValue + 2, 7);
            System.out.println("HashVlue: " + hashValue + " RValue: " +  RValue);
            client.sendREAD(Object);
        }
    }        
}
}

Most of the message handling on the server side is in ClientHandler. I'm less familiar with the client side, as I didn't write it. Obviously with this implementation, there is an InputMismatchException when reading the byte msgType on the server side. I also realized while searching for the solution, that at the very least I should be adding white space between all the fields for Scanner to parse them separately, but I still have issues.

Was it helpful?

Solution

Use a DataOutputStream and a DataInputStream. Instead of lines, use writeUTF() and readUTF(). For efficiency, put buffered streams underneath, and flush the output before you read.

OTHER TIPS

Scanner takes Input Streams such as System.in you are better off using BufferedReader here. E.g

BufferedReader reader = new BufferReader(new FileReader("temp"));

System.out.println(reader.readLine());

reader.close();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top