一、前言
实验目的
利用RMI技术对远程文件夹进行控制:可以增加文件(文本文件)、修改文件(文本文件)、删除文件、列出文件;统计该文件夹具有多少个文件、占用磁盘空间的总大小。
开发环境
- 操作系统:Windows 10 X64
- IDE:Intellij IDEA
二、准备
新建Java项目:File->New->Project
点击Next:
点击Next:
设置项目名称以及项目存储位置,点击Finish:
三、代码步骤
1. 远程接口定义
定义用于远程对象的接口 FileService。这个接口定义了客户机能够远程地调用的方法。远程接口和本地接口的主要差异在于,远程方法必须能抛出 RemoteException。具体方法如下:
FileService.java:
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface FileService extends Remote {
//列出文件
public String[] play() throws RemoteException;
//增加文件
public boolean addFile(String name) throws RemoteException;
//删除文件
public boolean deleteFile(String name) throws RemoteException;
//修改文件
public boolean alterFile(String name,String content) throws RemoteException;
//读取文件内容
public String readFile(String name) throws RemoteException;
//统计文件信息
public long[] fileInformation() throws RemoteException;
}
这些方法必须能抛出RemoteException,如果客户机和服务器之间的通信错误,则客户机将捕获此异常。
注:该接口本身继承了java.rmi包中定义的Remote接口。Remote接口本身没有定义方法,但通过继承它,我们说明该接口可以被远程地调用。
2. 实现远程接口
编写一个实现FileService接口的类 FileServiceImpl。
FileServiceImpl.java:
import java.io.*;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
/**
* 继承自UnicastRemoteObject,为远程对象的实现类
*/
public class FileServiceImpl extends UnicastRemoteObject implements FileService{
public FileServiceImpl() throws RemoteException {
super();
}
// 列出文件
@Override
public String[] play() throws RemoteException {
File file = new File("D://RMI");
String[] names=file.list();
return names;
}
// 增加文件
@Override
public boolean addFile(String name) throws RemoteException {
File file = new File("D://RMI",name);
if(!file.exists()){
try{
file.createNewFile();
return true;
}catch(IOException e){
e.printStackTrace();
}
}
return false;
}
// 删除文件
@Override
public boolean deleteFile(String name) throws RemoteException {
File file = new File("D://RMI",name);
if(file.exists()){
file.delete();
return true;
}
return false;
}
// 修改文件
@Override
public boolean alterFile(String name, String content) throws RemoteException {
FileWriter fw = null;
try{
fw = new FileWriter("D://RMI/"+name);
}catch(IOException e1){
e1.printStackTrace();
}
try{
fw.write(content,0,content.length());
}catch (IOException e2){
e2.printStackTrace();
}
//关闭流
try{
fw.close();
return true;
}catch (IOException e3){
e3.printStackTrace();
}
return false;
}
//读取文件内容
@Override
public String readFile(String name) throws RemoteException {
FileReader fr = null;
try{
fr = new FileReader("D://RMI/"+name);
}catch (FileNotFoundException e){
e.printStackTrace();
}
int ch = 0;
String filecontent = "";
try{
while((ch = fr.read())!=-1){
filecontent = filecontent + (char)ch;
}
}catch (IOException e){
e.printStackTrace();
}
//
try{
fr.close();
}catch (Exception e){
e.printStackTrace();
}
return filecontent;
}
//统计该文件夹具有多少个文件、占用磁盘空间的总大小
@Override
public long[] fileInformation() throws RemoteException {
File file = new File("D://RMI");
File[] files = file.listFiles();
long number = files.length;
long size = 0;
for(int i=0;i<number;i++){
size = size + files[i].length()/1024;
}
long[] information = {number,size};
return information;
}
}
注:在对文件进行读写操作后必须关闭用close()函数关闭流,不然可能会影响到delete操作,导致不能删除文件。
3. 编写在服务器上运行的主程序 Server.java。
创建服务器对象的初始实例,然后将对象的名称写到RMI命名注册表。
//创建服务器对象实例
FileService fileService = new FileServiceImpl();
//注册服务的端口
LocateRegistry.createRegistry(6600);
//绑定本地地址和服务器的路径
Naming.rebind("rmi://127.0.0.1:6600/FileService",fileService);
RMI命名注册表允许您将URL名称分配给对象以便客户机查找它们。要注册名称,需要调用在Naming类上定义的静态rebind方法。这个方法接受对象的URL名称以及对象引用。
名称字符串包含 rmi:// 前缀、运行RMI对象的服务器的计算机主机名和对象本身的名称。这里用了本机地址127.0.0.1。
完整代码如下:
Server.java:
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class Server {
public Server(){}
public static void main(String[] args){
try{
FileService fileService = new FileServiceImpl();
//注册服务的端口
LocateRegistry.createRegistry(6600);
//绑定本地地址和服务器的路径
Naming.rebind("rmi://192.168.1.102:6600/FileService",fileService);
System.out.println("开始服务!");
}catch(Exception e){
e.printStackTrace();
}
}
}
4. 编写客户端程序 Client.java。
使用RMI注册表查找远程对象。
//调用远程对象,RMI路径与接口必须与服务器配置一致
FileService fileService = (FileService)Naming.lookup("rmi://127.0.0.1:6600/FileService");
根据选择的操作,调用有远程接口定义的方法。完整代码如下:
Client.java:
import java.rmi.Naming;
import java.util.Scanner;
public class Client {
public Client(){}
public static void main(String[] args){
try{
//调用远程对象,RMI路径与接口必须与服务器配置一致
FileService fileService = (FileService)Naming.lookup("rmi://127.0.0.1:6600/FileService");
int choose;
Scanner input = new Scanner(System.in);
System.out.println("1.列出文件");
System.out.println("2.增加文件");
System.out.println("3.修改文件");
System.out.println("4.删除文件");
System.out.println("5.统计文件");
while(true){
System.out.println("请选择要进行的操作:");
choose = input.nextInt();
if(choose == 1){
String[] filename = fileService.play();
for(int i = 0;i < filename.length;i++){
System.out.println(filename[i]);
}
}
else if(choose == 2){
System.out.println("请输入要新增文件的名称:");
String name = input.next();
boolean flag = fileService.addFile(name);
if(flag == true){
System.out.println("创建成功!");
}
else{
System.out.println("创建失败!");
}
}
else if(choose == 3){
System.out.println("请输入要修改文件的名称:");
String name = input.next();
String filecontent = fileService.readFile(name);
System.out.println(filecontent);
System.out.println("请输入修改内容:");
String content = input.next();
boolean flag = fileService.alterFile(name,content);
if(flag == true){
System.out.println("修改成功!");
}
else{
System.out.println("修改失败!");
}
}
else if(choose == 4){
System.out.println("请输入要删除文件的名称:");
String name = input.next();
boolean flag = fileService.deleteFile(name);
if(flag == true){
System.out.println("删除成功!");
}
else{
System.out.println("删除失败!");
}
}
else if(choose == 5){
long[] information = fileService.fileInformation();
System.out.println("总共有文件夹:"+information[0]+"个.");
System.out.println("大小总计:"+information[1]+"KB.");
}
else{
System.out.println("无效操作!");
}
}
}catch (Exception ex){
ex.printStackTrace();
}
}
}
四、运行
1. 打开Server.java,点击Run,选择Run,在弹出框中选择Server。
运行结果:
2. 打开Client.java,点击Run,选择Run,在弹出框中选择Client。同上。
运行结果:
输入1,显示所有文件:
输入2,新增文件;输入文件名:
输入3,修改文件;输入文件名:
输入4,删除文件;输入文件名:
输入5,显示文件个数和所占磁盘大小: