扫描程序与OutputStreams的兼容性

时间:2014-04-22 19:59:41

标签: java io java.util.scanner java-io

我遇到了一个试图从DataOutputStream读取Scanner的问题。以下代码因输入不匹配异常而失败。

    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();

那么哪些输出流与Scanner兼容?是否有一个输出/输入流对,用于读写所有原始类型和字符串行?我真的想要一个不推荐使用的readLine()方法,并且我已经看到所有具有该方法的输入流都已弃用。

修改: 输入和输出流将跨客户端/服务器应用程序的套接字。以下是每一方的整个相关代码:

服务器

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);
        }
    }
}
}

客户端

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);
        }
    }        
}
}

服务器端的大多数消息处理都在ClientHandler中。我不熟悉客户端,因为我没有写它。显然,使用此实现时,在服务器端读取字节InputMismatchException时会有msgType。我在搜索解决方案时也意识到,至少我应该在Scanner的所有字段之间添加空格来分别解析它们,但我仍然有问题。

2 个答案:

答案 0 :(得分:2)

使用DataOutputStream和DataInputStream。而不是行,使用writeUTF()和readUTF()。为了提高效率,请将缓冲流放在下面,然后在读取之前刷新输出。

答案 1 :(得分:1)

扫描程序需要Input Streams,例如System.in,您最好在此使用BufferedReader。 E.g

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

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

reader.close();