我遇到了一个试图从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
的所有字段之间添加空格来分别解析它们,但我仍然有问题。
答案 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();